让我们说,我有一个名为session的NSURLSession,我想在downloadTaskWithRequest中更新我的UI。现在,案例1和案例2将会发生什么:
案例1:(dispatch_async)
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDownloadTask *task= [session downloadTaskWithRequest:request
completionHandler:^(NSURL *localFile, NSURLResponse *response, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{
// UI Update
});
}];
案例2:(使用dispatch_sync)
NSURLSessionDownloadTask *task= [session downloadTaskWithRequest:request
completionHandler:^(NSURL *localFile, NSURLResponse *response, NSError *error){
dispatch_sync(dispatch_get_main_queue(), ^{
// UI Update
});
}];
答案 0 :(得分:2)
tl; dr 第二种情况将等待UI更新完成。首先是更快。
<强> Deatailed 强>
dispathc_sync
阻止当前队列上的执行,直到调度任务完成。因此,如果主队列发生了巨大的事情,案例2将需要很长时间才能完成。但是,当完成处理程序完成其工作时(例如,如果您在UI更新调度之后执行某些操作),您确定UI已经更新。
此外,如果由于某种未知原因,您将session
配置为在主队列上调度完成块,则在第二种情况下您将遇到死锁。这是因为主队列是串行的,这意味着它一次只执行一个任务 - 所以完成处理程序将等待UI更新完成,并且UI更新将不会开始,直到完成处理程序没有完成。
dispatch_async
不会阻止执行流程。这意味着,您不会以任何方式获得死锁,并且完成块执行时间将不依赖于UI更新持续时间。但是,即使完成处理程序已完成,您也不知道UI更新是否完成。
但是,如果您的completionHandler
已分派到主队列,则更新的UI将仅在completionHandler
完成后执行。
<强>击穿强> 案例二:
completionHandler:^(NSURL *localFile, NSURLResponse *response, NSError *error){
//Some code
//1
dispatch_sync(dispatch_get_main_queue(), ^{
//2
// UI Update
//3
});
//Some code
//4
}];
到达//1
,到达//2
,到达//3
,到达//4
。执行顺序有保证。无论如何 - 无论是这样还是根本不执行。
案例一:
completionHandler:^(NSURL *localFile, NSURLResponse *response, NSError *error){
//Some code
//1
dispatch_async(dispatch_get_main_queue(), ^{
//2
// UI Update
//3
});
//Some code
//4
}];
到达//1
。保证。在那之后变种可能。
到达//2
,到达//4
,到达//3
。
要么
到达//4
,到达//2
,到达//3
要么
到达//2
,到达//3
,到达//4
。
如果在主队列上调度completionBlock
,则第二个将始终如此。
如果不清楚的话,请随意询问
答案 1 :(得分:1)
请注意dispatch_get_main_queue() is a serial queue,
因此,每当您调度一个块来执行它时,它就会到达行的末尾,并在处理器按顺序执行前面的所有其他任务后执行。
当你dispatch_async
一个块(任务)时,恰好会发生这种情况:任务将放在行的末尾,dispatch_async
之后的代码将继续执行。一旦主线程完成该调度任务前面的所有任务(运行结束循环),您的任务就会执行
然而,当你dispatch_sync
时,当前线程(在你的情况下是主线程)将在等待调度任务执行时被阻塞。正如@dan在评论中提到的,因为你当前在主线程中,而你dispatch_sync
一个任务到主线程,你将陷入僵局。这是因为你在主线程的末尾添加了一个任务,而主线程中行前面的任务正在等待最后一个任务执行 - 但它永远不会因为它在排队等待。 / p>
因此,如果您想在单独的线程上执行任务,但又不希望它以异步方式发生,那么您将使用dispatch_sync
。只要确保你永远不会调度到与当前线程相同的线程