dispatch_async和异步请求的问题

时间:2012-03-27 09:20:34

标签: ios multithreading asynchronous grand-central-dispatch

所以第一个问题是dispatch_async如何确定使用哪个线程?只是随机挑选它?我需要做一些解析和核心数据的东西,所以我不想阻止UI线程并使用dispatch_async,但之后我发送NSURLRequest来获取更多数据,回调永远不会调用(可能是因为线程已经死了)。

那么制作它的好方法是什么?我无法使用

sendAsynchronousRequest:queue:completionHandler: 

因为部署操作系统是4.现在我只是在

中发送请求
dispatch_async(dispatch_get_main_queue(), ^{
});

位于dispatch_async(myQueue)块内,它执行所有解析并保存到核心数据。但它对我来说似乎不对,我的意思是应该有一种方法来使用dispatch_async并告诉它不要杀掉它,对吗?因为使用同步请求不是一种选择。

3 个答案:

答案 0 :(得分:12)

  

所以第一个问题是dispatch_async如何确定使用哪个线程?

使用GCD时不应该考虑线程。这些都是幕后处理的。您认为在队列中,您将传递给dispatch_async以及要执行的块。 GCD队列会对一个线程进行映射,但您不必担心幕后发生的事情--GCD会为您处理所有这些事情。

至于你认为的代码看起来与此相似:

dispatch_async(myQueue, ^{
    // Do some stuff off the main queue

    dispatch_async(dispatch_get_main_queue(), ^{ 
        // Do something with the UI
    });
});

根本没有没有错误。您不必担心发送到myQueue的块运行的线程可能会被终止。队列将保持不变,直到块完成运行。您在原始调度中调度到主队列的事实很好 - 主队列上的工作将很愉快地运行。

我想你也在问为什么在异步调度中使用NSURLRequest时你会看到它不会调用回调。那将是因为它紧密耦合到当前的运行循环,如果你当前在后台线程(你的myQueue将运行),那么该运行循环将不再运行,直到另一个块被放置在队列上。所以你的回调永远不会运行。

我鼓励你去阅读更多关于GCD以及async vs sync实际意味着什么,因为我觉得你可能还没有完全理解它。我回答了类似的问题here

答案 1 :(得分:3)

在块中使用sendAsynchronousRequest:...时,块将在异步请求回调被触发之前终止。

由于您已经在后台线程中,如何使用该线程中的同步方法 来获取数据 - +[NSURLRequest sendSynchronousRequest:returningResponse:error:],甚至更简单,+[NSData dataWithContentsOfURL:]

您可以在后台线程上运行的块中调用这些,并且在调用完成之前块不会继续。然后,您可以通过回调主队列来更新UI:

dispatch_async(yourQueue, ^{
    // Do some stuff

    NSData * fetchedData = [NSData dataWithContentsOfURL: someURL];

    // Do some more stuff with the data

    dispatch_async(dispatch_get_main_queue(), ^{
       // Do some stuff on the main queue
    }
});

答案 2 :(得分:0)

你是对的,问题是该线程已经死了,因为NSURLConnection在其生命周期内不会让它保持活着状态。连接将在返回时被丢弃。 你可以用一些黑魔法明确地保持线程活着;)并在你完成后释放线程。在这种情况下,通过在成功或出错时将_isFinishedLoading设置为true。

因此,在这种情况下,使用块时不关心线程是不正确的,因为NSURLConnection并不真正兼容。然而,块非常有用,因为框架会根据底层硬件和可用资源为您选择最佳线程。

NSURLConnection* connection = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
[connection start];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
_isFinishedLoading = NO;
while (!_isFinishedLoading)
{
    [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}