2013-04-11 58 views
2

我有一个在后台线程上调用的方法foo:。此方法只是向服务器发送请求,并在检索数据后对这些数据执行一些计算并返回。在这种情况下,我更喜欢使用sendSynchronousRequest:因为此方法很方便,并且线程是否被阻塞并不重要。但是,该响应包含一个“位置”标题字段,该字段将重定向到另一个页面。我想读取响应以在重定向之前获取这些“Set-Cookie”标题字段。看来,同步方法不允许我。如何在后台线程上执行异步请求?

我试图使用异步的并实现NSURLConnectionDataDelegate,但线程完成之前调用委托的这些方法。 (我想苹果公司实现异步操作的方式是在新线程上执行那些耗时的工作)

有什么办法可以解决这个问题吗?由于在主线程上执行异步请求可能会增加我的程序的复杂性。

foo的:方法是一种像这样

- (Result *)foo 
{ 
    NSURLMutableRequest * request = blablabla; 
    //Do something to initialize the request 
    NSData *data = [NSURLConnection sendSynchronousRequest:request 
             returningResponse:&response 
                error:&error]; 

    //Do something with the data 

    Result *result = [[Result alloc] init] autorelease]; 
    //fill the result 

    return result; 
} 
+0

不确定为什么您认为在主线程上执行异步请求可能会增加程序的复杂性。创建后台线程通常只有在您需要执行长时间或计算密集型任务时才有意义,因为线程很快完成,这似乎不是这种情况。 – 2013-04-11 07:45:38

+0

正如你所提到的,foo方法是一个在计算密集型任务中调用的中间方法,我觉得它应该不在主线程中执行。 – Poligun 2013-04-11 08:22:37

回答

3

你可以使用一个大中央调度信号等到异步请求返回:

- (Result *)foo 
{ 
    NSMutableURLRequest * request = [[NSMutableURLRequest alloc] init]; 
    // set request's properties here 

    __block Result *result; 
    dispatch_semaphore_t holdOn = dispatch_semaphore_create(0); 
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
     if (error) 
     { 
      // handle error 
     } 
     else 
     { 
      result = [[Result alloc] initWithData:data]; 
     } 
     dispatch_semaphore_signal(holdOn); 
    }]; 

    dispatch_semaphore_wait(holdOn, DISPATCH_TIME_FOREVER); 

    return result; 
} 

注:此代码需要iOS 4.0+和ARC!

0

您可以创建自己的NSRunLoop,做你的要求有。完成请求后停止运行循环。

或者如果你是懒惰和我一样,不想与运行循环的一塌糊涂,只是把主线程的连接:

dispatch_async(dispatch_get_main_queue(), ^(void){ 
    self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
    [connection start]; 
} 
0

你可以找到一个小而简单的课程,让你在github上做到这一点。它提供了两个主要对象 - 设计用于运行后台提取的NSOperationsQueue管理器和NSOperation子类。如前所述,如果你所做的只是获取,你可以在主线程上做到这一点。但是如果你也想做数据处理,那么这个项目会让你在完成的方法中做到这一点。

OperationsRunner类的一个不错的属性是您可以随时取消操作(例如用户点击后退按钮),并且所有内容都快速拆除,不会发生拖延或泄漏。然而,如果你所做的只是这一个获取和一个进程,那么你可以像其他人说的那样只是获取主线程中的数据,一旦你拥有了它,然后将一个“处理”块分派到其中一个并发系统线程,以及处理完成后,向主线程发送另一条消息,告诉您工作已完成。

相关问题