Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c GCD和异步NSURL连接_Objective C_Ios_Grand Central Dispatch - Fatal编程技术网

Objective c GCD和异步NSURL连接

Objective c GCD和异步NSURL连接,objective-c,ios,grand-central-dispatch,Objective C,Ios,Grand Central Dispatch,我知道如果我创建一个NSURLConnection(标准异步连接),它将在同一个线程上回调。目前这是我的主线程。(工作也很好) 但我现在正在为其他东西使用相同的代码,我需要保持我的UI整洁 如果我这样做 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* and inside here, at some NSURLConnection is created */ })

我知道如果我创建一个NSURLConnection(标准异步连接),它将在同一个线程上回调。目前这是我的主线程。(工作也很好)

但我现在正在为其他东西使用相同的代码,我需要保持我的UI整洁

如果我这样做

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    /* and inside here, at some NSURLConnection is created */


});
。。是否有可能创建了NSURLConnection,但我的线程在url连接返回之前消失了


我是GCD的新手。在我的url连接返回之前,如何使线程保持活动状态,或者是否有更好的方法可以这样做?

首先,您的块和其中使用的每个变量都将复制到GCD,因此代码将不会在线程上执行,而是在全局队列上执行

如果要将数据返回主线程,可以在获取数据后嵌套异步调用:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]];
    NSURLResponse *response;
    NSError *error;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (error) {
        // handle error
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        // do something with the data
    });
});
但是为什么不使用NSURLConnection的内置异步支持呢?您需要一个NSOperationQueue,但如果您正在进行大量的网络回迁,则无论如何都可以这样做:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:self.queue // created at class init
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
                           // do something with data or handle error
                       }];

就我个人而言,我使用像AFNetworking或ASIHTTPRequest这样的库使联网更加容易,这两个库都支持块(前者使用GCD,而且更现代一些)。

所以真正的问题不是块运行的线程的生命周期,事实上,这个特定的线程不会配置并运行runloop来接收从连接返回的任何事件

那么你如何解决这个问题呢?有不同的选择可以考虑。我可以列出一些,我相信其他人会列出更多

1-您可以在此处使用同步连接。一个缺点是,您不会得到用于身份验证、重定向、缓存等的回调(同步连接的所有正常缺点)。另外,每个连接当然会在一段时间内阻塞一个线程,因此,如果您正在执行大量这些操作,则可能会同时阻塞几个线程,这很贵

2-如果您的连接很简单,并且使用的是iOS5,则可以使用以下方法:

+ (void)sendAsynchronousRequest:(NSURLRequest *)request
                          queue:(NSOperationQueue*) queue
              completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))
这将启动一个异步连接,然后允许您指定一个完成处理程序(用于成功或失败)一个NSOperationQueue,您希望在其上调度该块

同样,您的缺点是无法获得身份验证、缓存等所需的回调,但至少不会有线程被正在运行的连接阻塞

3-iOS5的另一个选项是为所有代理回调设置队列

-(void)setDelegateQueue:(NSOperationQueue*)队列NS\u可用(10\u 7,5\u 0)

如果使用此方法,则所有委托方法都将在指定的NSOperationQueue的上下文中执行。因此,这类似于选项#2,希望您现在获得所有委托方法来处理身份验证、重定向等

4-您可以设置自己控制的线程,专门用于管理这些连接。在设置该线程时,需要适当地配置runloop。这在iOS4和ios5中可以很好地工作,并且显然会提供您想要处理的所有委托回调

5-您可能会想,异步连接处理的哪些部分真正影响了您的UI。通常情况下,启动连接或接收委托回调的成本并不高。昂贵(或不确定)的成本通常是在处理最终收集的数据时产生的。这里要问的问题是,通过在某个队列上调度一个块来启动一个异步连接(该连接将立即关闭并在另一个线程上执行),您真的节省了时间吗

因此,您可以从主线程启动连接,接收主线程上的所有委托回调,然后在这些委托方法的实现中,启动您需要在其他队列或线程上执行的任何昂贵的工作

比如说:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {      
        // go ahead and receive this message on the main thread
        // but then turn around and fire off a block to do the real expensive work

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

         // Parse the data we've been collecting

        });

    }

同样,这是不全面的。根据您在这里的具体需求,有许多方法可以处理此问题。但是我希望这些想法能有所帮助。

正如回答为什么您的线程正在显示(供将来参考)NSURLConnection需要一个runloop。如果你加上

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];

您会看到连接正常运行,线程不会消失,直到连接完成。

非常全面的响应。第5点是我的问题-我优化得太早了(这不是一个编程错误吗?)。您还解释了这一点,因为我没有在这个线程上配置运行循环。谢谢你也指出了替代方案。谢谢你的提示。我的dispatch\u async并不是在我创建连接的地方(我同意这在我的问题中并不清楚),在创建url连接之前,dispatch在调用堆栈中的时间要早一点。我认为我真正需要的是重新审视我的设计——因为我在不同的上下文中使用RemoteImage类,我需要使它在内部异步。我非常喜欢这种方法。很好的回答
dispatch_queue_t queue = dispatch_get_global_queue(  DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
        [btnCreateSmartList setEnabled:NO];
        [dbSingleton() createEditableCopyOfDatabaseIfNeeded];
        [dbSingleton() insert_SMART_PlaceList:txtListName.text :0:txtTravelType.text:          [strgDuration intValue]:strgTemprature:Strgender:bimgdt];
        [self Save_items];
//*********navigate new
            dispatch_async(dispatch_get_main_queue(), ^{
                [activityIndicator stopAnimating];
                [self performSelector:@selector(gonext_screen) withObject:nil afterDelay:0.0];
            });
        });