應用有一個簡單的需求,即在後台做文件下載等一系列操作,過程中在主頁面刷新進度條,全部完成後彈出對話框提示用戶
這個需求顯然必須用到多線程,在網上搜索了一番,在ios裡實現多線程主要有3種方式:
1、NSThread,以及在此基礎上封裝的performSelector方法,如performSelectorInBackground和performSelectorOnMainThread等簡便方法
2、NSOperation,這個方式我從來沒用過,不了解
3、GCD,今天我改成了這個實現方式,本文主要總結關於GCD的用法
本來我是用NSThread + Notification來實現線程切換,不過隨著UI變得復雜,代碼也越來越不清晰了。主要是NSThread有以下幾個缺點:
1、經常需要配合Notification一起使用,如果流程比較復雜,系統中會有很多事件,理解起來很不直觀
2、performSelector方法的參數,只能接受SEL,不能傳遞block進去,所以系統中需要很多“跳板方法”
3、偵聽事件的方法,只能接受一個參數即notification,然後取出userInfo,類型也限定為NSDictionary,復雜交互時,傳參很不方便
相比之下,GCD可以克服上面的幾個問題,不需要配合notification就能工作,而且block可以形成閉包,傳參也很方便
更重要的是,GCD是apple官方推薦的方式,所以很多第三方組件都是用GCD來實現的,應用使用GCD有時候就可以和第三方組件很好地配合
我今天才剛開始接觸,對API也了解得不全,主要有4個函數比較常用,可以滿足一般的場景了(GCD的API是C風格,不是objective-c風格)
dispatch_async()和dispatch_sync,就是開啟新線程的API,前者是立刻返回,不阻塞當前線程;後者則是同步調用,會阻塞當前的線程,所以在UI Thread裡,要小心調用dispatch_sync()函數
這2個函數都接受2個參數,第1個是線程,第2個是block。block就不用多解釋了,為了傳第1個參數,就用到下面2個API
dispatch_get_global_queue,dispatch_get_main_queue,前者是整個進程(應用)共享的子線程,後者就是UI Thread,我感覺使用這4個API,就足夠應付一般的需求了
下面貼一段示例代碼:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ BOOL needBackup = [self.backupDelegate checkNeedBackup];// 跑在子線程 dispatch_async(dispatch_get_main_queue(), ^(void){ if(needBackup){ UIAlertView *confirmBackupAlert = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@backup_confirm_alert_view_message, @) delegate:mainViewDelegate cancelButtonTitle:NSLocalizedString(@button_cancel, @) otherButtonTitles:NSLocalizedString(@button_confirm, @), nil]; confirmBackupAlert.tag = ALERT_TAG_CONFIRM_BACKUP; [confirmBackupAlert show]; }else{ UIAlertView *noNeedBackupAlert = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@backup_no_need, @) delegate:mainViewDelegate cancelButtonTitle:NSLocalizedString(@button_iknow, @) otherButtonTitles:nil]; noNeedBackupAlert.tag = ALERT_TAG_BACKUP_NO_NEED; [noNeedBackupAlert show]; } }); });