GCD(Grand Central Dispatch)

如果我们有一件工作,想要在某条指定的thread上执行,现在最简单的方法大概就是调用GCD。GCD其实包含相当多的API,是一群C function的组合,其中,我们最常用的是dispatch_async

dispatch_async

dispatch_async这个function,可以让我们选择要在哪个指定的thread 上,用非同步的方式执行一个block。比方说,我们现在在前景,但是想要在背景执行一件工作,就会这么写:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
  dispatch_get_main_queue(), ^{
    [someObject doSomething];
});

dispatch_get_global_queue这个function 会让系统根据目前的状况,在适当时机建立一条thread,第一个参数是这条thread 执行工作的优先程度,优先程度会从2 到-2 安排,2 为最重要,-2 为最不重要;至于第二个参数则是保留参数,目前都没有作用,直接填0 即可。

如果我们已经在背景了,想要在main thread执行工作,那么,就把dispatch_get_global_queue换成dispatch_get_main_queue

dispatch_async(dispatch_get_main_queue(), ^{
    [someObject doSomethingHere];
});

我们经常会先让某个工作在背景执行,执行完毕之后,再继续在main thread 更新UI,让用户知道这件工作已经执行完毕,我们便可以组合前面两个 调用:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [someObject doSomethingInBackground];
dispatch_async(dispatch_get_main_queue(), ^{
        [someObject doSomethingOnMainThread];
    });
});

如果我们想要让好几件工作都在背景执行,而每件工作并非平行执行,而是一件工作做完之后,再继续下一件,我们便可以使用serial 的queue。像这样:

dispatch_queue_t serialQueue = \
    dispatch_queue_create("com.kkbox.queue", DISPATCH_QUEUE_SERIAL);

dispatch_async(serialQueue, ^{
    [someObject doSomethingHere];
});

dispatch_async(serialQueue, ^{
    [someObject doSomethingHereAsWell];
});

dispatch_sync

不同于dispatch_async会做平行处理,呼叫dispatch_sync的时候,则是会先把dispatch_sync的这个block做完之后,才继续执行到程式的下一行。

我们在呼叫dispatch_sync的时候要特别注意:如果我们已经在某一条thread中,而调用dispatch_sync时所传入的thread就是目前所在的thread,那么会造成程式执行时卡死。比方说,我们已经在main thread了,但我们却呼叫:

dispatch_sync(dispatch_get_main_queue(), ^{

    [someObject doSomethingHere];

});

这段程式就会卡住。我们可以用NSThread的一些method检查我们目前正在哪条thread,例如使用+isMainThread检查是否是main thread。

其他一些好用的API

dispatch_async`dispatch_sync相较,底下这些API会比较少用,但是可以解决不少麻烦的问题。

dispatch_once

dispatch_once保证某个block只会被执行一次,现在大家最常使用这个特性实作singleton。我们在「再谈Singleton」这一章当中也提过。

dispatch_after

可以延后执行某个block 在某个指定的dispatch queue 上执行,我们可以用这个function 代替timer。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
  dispatch_get_main_queue(), ^{
    [someObject doSomething];
});

dispatch_apply

如果我们想要重复执行某个block,就可以考虑使用dispatch_applydispatch_apply有三个参数,第一个参数是要执行的次数,第二个参数则是要在哪个dispatch queue上执行:就像前面提到的,如果想要平行执行,就调用dispatch_get_global_queue,如果想要依序执行,就建立一个serial的dispatch queue。

results matching ""

    No results matching ""