2

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

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

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

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;
}
4

4 回答 4

3

您可以使用 Grand Central Dispatch 信号量来等待异步请求返回:

- (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!

于 2013-04-11T09:21:08.250 回答
0

您可以创建自己的NSRunLoop并在那里完成您的请求。完成请求后停止运行循环。

或者,如果您像我一样懒惰并且不想弄乱运行循环,只需将您的连接放在主线程上:

dispatch_async(dispatch_get_main_queue(), ^(void){
    self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [connection start];
}
于 2013-04-11T07:45:24.067 回答
0

查看[NSCondition]哪些使您能够等待和信号线程

基本上你NSCondition在你将拥有的块中分配一个 and ,[condition wait];这将导致线程等待。然后,当异步操作完成时,您调用[condition signal];它将发出等待线程继续的信号。

http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/NSCondition_class/Reference/Reference.html

于 2013-04-11T07:41:08.787 回答
0

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

OperationsRunner 类的一个很好的属性是您可以随时取消操作(例如,当用户点击后退按钮时),所有内容都可以快速删除,不会出现停滞或泄漏。

但是,如果您所做的只是一次获取和一个进程,那么您可以像其他人所说的那样仅在主线程上获取数据,一旦拥有它,然后将“处理”块分派给并发系统线程之一,当该处理完成后,向主线程发送另一条消息,告诉您工作已完成。

于 2013-04-11T12:30:20.363 回答