GCD异步方法的行为不可理解

时间:2014-05-17 18:27:33

标签: ios multithreading

我的iOS应用程序中有以下内容。 我正在学习GCD。所以,尝试简单的事情。

这里的输出令我困惑。 为什么总是第2组语句首先出现然后是1.? 即使我将这两个任务发送给GCD,我首先要调度1.先设置。这不是一项艰巨的任务,因此1.set和2.set将在时间上重叠。打印正在运行的线程只是一个简单的任务。

我已经多次运行它,期望它会在线程环境中产生不同的结果。

请描述一下。

2. Crnt Thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
2. Main thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
1. Crnt Thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
1. Main thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
3. Crnt Thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
3. Main thread = <NSThread: 0x10920fee0>{name = (null), num = 1}

代码在这里:

void displayAlertView(void *paramContext)
{

    NSLog(@"3. Crnt Thread = %@",[NSThread currentThread]);
    NSLog(@"3. Main thread = %@", [NSThread mainThread]);
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    dispatch_queue_t myQueue = dispatch_get_main_queue();
    AlertViewData *contextData = (AlertViewData *)malloc(sizeof(AlertViewData));
    dispatch_async(myQueue,^(void){
        NSLog(@"1. Crnt Thread = %@",[NSThread currentThread]);
        NSLog(@"1. Main thread = %@", [NSThread mainThread]);
    });
    if(contextData != NULL)
    {
        NSLog(@"2. Crnt Thread = %@",[NSThread currentThread]);
        NSLog(@"2. Main thread = %@", [NSThread mainThread]);

        dispatch_async_f(myQueue, contextData, displayAlertView);
    }

    return YES;
}

1 个答案:

答案 0 :(得分:0)

首先出现“2”语句,因为在异步块有机会设置和运行之前,代码才会执行​​。这就是dispatch_async的重点。这样的代码在另一个线程上运行,而当前线程继续以其快乐的方式继续运行。

如果您更新了两个代码块以使用记录100个日志语句的循环,那么您可能会看到一些混合的“1”和“2”语句。

但是只有两个日志,它们发生得如此之快,“2”日志在块之前完成,“1”日志有机会启动。请查看日志中的时间戳以查看。

<强>更新

以上是在假设myQueue是后台队列的情况下编写的。正如马丁指出的那样,这是主要的队列。由于它是主队列,答案有点不同。

由于您正在对主队列执行异步调用,因此所有操作都在同一主线程上完成。每次调用dispatch_async就像将其添加到行尾。

当前运行的代码位于行首。当您使用“1”日志为块调用dispatch_async时,该块将添加到行的末尾,并在当前代码完成时运行。然后为{3}日志调用dispatch_async_f。那些被添加到行的末尾(在“1”日志之后)。

因此,一旦当前的runloop完成(并且didFinishLaunchingWithOptions`方法返回),则运行下一行。这是你的“1”日志。完成后,运行队列中的下一个块(“3”日志)。