在dispatch_async和dispatch_sysnc中更新UI时的区别

时间:2015-11-19 16:59:30

标签: ios multithreading grand-central-dispatch

让我们说,我有一个名为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    
                                               });
}];

2 个答案:

答案 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。只要确保你永远不会调度到与当前线程相同的线程