GCD/Block

GCD

唐巧的博客

block 的定義

block 的定義有點象函數指針,差別是用 ^ 替代了函數指針的 * 號,如下所示:

// 申明變量
(void) (^loggerBlock)(void);

// 定義
loggerBlock = ^{ 
   NSLog(@"Hello world");
};

// 調用
loggerBlock();

但是大多數時候,我們通常使用內聯的方式來定義 block,即將它的程序塊寫在調用的函數裏面,例如這樣:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
     // something
});

從上面大家可以看出,block 有如下特點:

  • 程序塊可以在代碼中以內聯的方式來定義。
  • 程序塊可以訪問在創建它的範圍內的可用的變量。

系統提供的 dispatch 方法

爲了方便地使用 GCD,蘋果提供了一些方法方便我們將 block 放在主線程 或 後臺線程執行,或者延後執行。使用的例子如下:

//  後臺執行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
     // something
});
// 主線程執行:
dispatch_async(dispatch_get_main_queue(), ^{
     // something
});
// 一次性執行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // code to be executed once
});
// 延遲 2 秒執行:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // code to be executed on the main queue after delay
});

dispatch_queue_t 也可以自己定義,如要要自定義 queue,可以用 dispatch_queue_create 方法,示例如下:

dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
dispatch_async(urls_queue, ^{
     // your code
});
dispatch_release(urls_queue);

另外,GCD 還有一些高級用法,例如讓後臺 2 個線程並行執行,然後等 2 個線程都結束後,再彙總執行結果。這個可以用 dispatch_group, dispatch_group_async 和 dispatch_group_notify 來實現,示例如下:

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
     // 並行執行的線程一
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
     // 並行執行的線程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
     // 彙總結果
});

修改 block 之外的變量

默認情況下,在程序塊中訪問的外部變量是複製過去的,即寫操作不對原變量生效。但是你可以加上 __block 來讓其寫操作生效,示例代碼如下:

__block int a = 0;
void  (^foo)(void) = ^{
     a = 1;
}
foo();
// 這裏,a 的值被修改爲 1

後臺運行

使用 block 的另一個用處是可以讓程序在後臺較長久的運行。在以前,當 app 被按 home 鍵退出後,app 僅有最多 5 秒鐘的時候做一些保存或清理資源的工作。但是應用可以調用 UIApplicationbeginBackgroundTaskWithExpirationHandler方法,讓 app 最多有 10 分鐘的時間在後臺長久運行。這個時間可以用來做清理本地緩存,發送統計數據等工作。

讓程序在後臺長久運行的示例代碼如下:

// AppDelegate.h 文件
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
// AppDelegate.m 文件
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self beingBackgroundUpdateTask];
    // 在這裏加上你需要長久運行的代碼
    [self endBackgroundUpdateTask];
}
- (void)beingBackgroundUpdateTask
{
    self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundUpdateTask];
    }];
}
- (void)endBackgroundUpdateTask
{
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
    self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}
發佈了36 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章