GCD (一)
GCD中有三種隊列類型:
- The main queue:跟主線程功能相同钱磅,在實際運用的時候揍堰,提交到main queue的任務會在主線程里面執(zhí)行怕敬。main queue可以調用dispatch_get_main_queue()來獲得柒凉。因為main queue是跟主線程相關的,因此我們可以知道這事一個串行隊列债朵。
- Global queues:全局隊列是并發(fā)隊列子眶,并由整個進程共享。進程中存在三個全局隊列優(yōu)先級:高序芦,中(default)臭杰,低。
- 用戶隊列:用戶隊列是用函數(shù) dispatch_queue_create 創(chuàng)建的谚中,這些隊列是串行的渴杆,可以用來完成同步執(zhí)行寥枝,有點像操作系統(tǒng)里面的互斥。
創(chuàng)建隊列
要使用用戶隊列的時候我們要調用函數(shù)來創(chuàng)建一個磁奖。
dispatch_queue_create(<#const char *label#>, <#dispatch_queue_attr_t attr#>);
函數(shù)的第一個屬性是一個標簽囊拜,是為了debug用的,最好用倒置域名來命名隊列点寥。第二個參數(shù)沒用艾疟,現(xiàn)在傳入NULL就可以了
提交作業(yè)(Job)
向一個隊列提交作業(yè)很簡單:調用 dispatch_async 函數(shù),傳入一個隊列跟block敢辩。
//異步
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self dosomeThing];
NSLog(@"dispatch_async in ViewDidLoad");
//一般在執(zhí)行完job任務之后蔽莱,可能會刷新界面,這時候會回到主線程
dispatch_async(dispatch_get_main_queue(), ^{
//更新一下你的界面咯
NSLog(@"update UI in main_queue");
});
});
dispatch_async 會直接返回戚长,block會在后臺異步執(zhí)行盗冷。
//同步
//會等待block里面的代碼執(zhí)行完之后再返回
//利用__block修飾符,可以從block 里面獲取一個值同廉,活著從界面控制獲取一個值
__block NSString *str ;
dispatch_sync(dispatch_get_main_queue(), ^{
str = [_myLabel.text copy];
});
//利用嵌套的block來中止后臺線程仪糖,然后從主線程中獲取值,在交給后臺進程處理
dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(dispatch_get_main_queue(), ^{
NSString *str = [_myLabel.text copy];
dispatch_async(bgQueue, ^{
//use
});
});
有異步迫肖,那么就肯定同步锅劝,這個函數(shù)會一步一步執(zhí)行,就是她會等待block的代碼完成之后蟆湖,才會執(zhí)行函數(shù)后面的代碼故爵。
不再適用鎖(Lock)
在這里,我先解釋一下dispatch_sync 和 dispatch_async 的工作流程
dispatch_sync(queue, block) 做了兩件事情
* 將block添加到queue 隊列中隅津;
* 阻塞調用這個函數(shù)的進程诬垂,等待block執(zhí)行完畢,再返回調用進程伦仍。
dispatch_async(queue, block) 也做了兩件事情
* 將block添加到queue 隊列中结窘;
* 直接回到調用線程(這時候就不阻塞了)
那我們怎么實現(xiàn)同步鎖呢?
其實只需要我們的數(shù)據(jù)在同一個串行同步隊列里面執(zhí)行就可以了充蓝。
為了實現(xiàn)這樣的功能隧枫,我們就需要DISPATCH_QUEUE_SERIAL 隊列,也就是用戶隊列谓苟。
_syncQueue = dispatch_queue_create("com.kingandyoga.syncQueue", NULL);
//get 方法
- (NSString *)someString
{
__weak NSString *localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString;
}
//set 方法
- (void)setSomeString:(NSString *)someString
{
dispatch_sync(_syncQueue, ^{
_someString = someString;
});
}
然而設置方法不一定非得是同步的官脓,設置實例變量的 block 沒有返回值,所以可以將此方法改成異步:
- (void)setSomeString:(NSString *)someString
{
dispatch_async(_syncQueue, ^{
_someString = someString;
});
}
這次只是把 dispatch_sync 改成 dispatch_async娜谊,從調用者來看提升了執(zhí)行速度确买。但正是由于執(zhí)行異步派發(fā)
dispatch_async 時會拷貝 block斤讥,當拷貝 block 的時間大于執(zhí)行 block 的時間時纱皆,dispatch_async 的速度會比 dispatch_sync 速度更慢湾趾。所以實際情況應根據(jù) block 所執(zhí)行任務的繁重程度來決定使用 dispatch_async 還是 dispatch_sync。