上篇記錄了GCD的各種基本使用方法及特點,下面是GCD在項目中的常用場景
1、創建單例 dispatch_once
static People *sharePeople = nil;
+ (instancetype)sharePeople{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"oncetoken");//這裏的代碼只會執行一次
sharePeople = [[self alloc]init];
});
return sharePeople;
}
2、延遲執行 dispatch_after (異步)
函數原型
參數 when 延遲執行的時間
參數 quene 在哪個隊列中執行
參數 block 延遲執行的內容
dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
NSLog(@"開始"); double delayInSeconds = 2.0; dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, mainQueue, ^{ NSLog(@"延時執行的2秒"); }); NSLog(@"結束");執行結果:
2016-12-27 15:37:32.509 GCD[1547:228385] 開始
2016-12-27 15:37:32.509 GCD[1547:228385] 結束
2016-12-27 15:37:34.510 GCD[1547:228385] 延時執行的2秒
注意:延遲執行在iOS中一般還可以通過下面的方法或者NSTimer來實現
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
但這個方法並不是安全的,因爲這個方法或者是NSTimer都需要有一個runloop來實現,而只有主線程在創建的時候回默認自動運行一個runloop,普通的子線程是沒有的,一旦這兩種方式在子線程中調用,則延遲方法裏面的內容就永遠不會執行。
相對來說GCD是安全的
3、併發地執行循環迭代 dispatch_apply
代替for循環 要求,循環次數固定並且循環執行的次序無關,這是可以用dispatch_apply提高效率(併發執行)
原來的for循環
int i;
int count = 10;
for (i = 0; i < count; i++) {
printf("%d ",i);
}
這是輸出
0 1 2 3 4 5 6 7 8 9
同dispatch_apply代替
// 獲得全局併發queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
size_t count = 10;
dispatch_apply(count, queue, ^(size_t i) {
printf("%zd ", i);
});
可能就會輸出
0 1 3 2 4 5 6 8 7 9
4、在子線程中調用下載圖片等耗時操作,下載完成後在主線程刷新界面
// 異步下載圖片
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:@"http://image.baidu.com/search/detail?ct=503316480&z=0&tn=baiduimagedetail&ipn=d&cl=2&cm=1&sc=0&lm=-1&ie=gbk&pn=0&rn=1&di=20652390440&ln=30&word=ͼƬ&os=3812566282,1648699000&cs=214931719,1608091472&objurl=http%3A%2F%2F4493bz.1985t.com%2Fuploads%2Fallimg%2F150127%2F4-15012G52133.jpg&bdtype=0&simid=3354004378,369260611&pi=0&adpicid=0&fr=ala&ala=1&alatpl=others&pos=1"];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
// 回到主線程顯示圖片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});
這裏可能會有這種情況,某界面需要兩張或多張圖片,當所有的圖片加載完成後才刷新界面,這時可以用Dispatch Group來實現
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 異步下載圖片
dispatch_async(queue, ^{
// 創建一個組
dispatch_group_t group = dispatch_group_create();
__block UIImage *image1 = nil;
__block UIImage *image2 = nil;
// 關聯一個任務到group
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下載第一張圖片
NSString *url1 = @"http://car0.autoimg.cn/upload/spec/9579/u_20120110174805627264.jpg";
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url1]]];
});
// 關聯一個任務到group
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下載第一張圖片
NSString *url2 = @"http://hiphotos.baidu.com/lvpics/pic/item/3a86813d1fa41768bba16746.jpg";
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url2]]];
});
// 等待組中的任務執行完畢,回到主線程執行block回調
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
self.imageView1.image = image1;
self.imageView2.image = image2;
// 千萬不要在異步線程中自動釋放UIImage,因爲當異步線程結束,異步線程的自動釋放池也會被銷燬,那麼UIImage也會被銷燬
});
});