<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在實際開發中,經常需要在幾個任務全部執行完成之後,在執行後續操作,在 iOS 中,我們可以通過 NSOperation 等達到這一目的。在本篇文章中,我們會介紹如何通過 dispatch_group_enter 和 dispatch_group_leave 來實現這一功能,以及使用過程中遇到的坑。
通過一個例子來看下如何使用 dispatch_group_enter 和 dispatch_group_leave:
{ // 首先 需要建立一個執行緒組 dispatch_group_t group = dispatch_group_create(); // 任務1 dispatch_group_enter(group); NSURLSessionDataTask *task1 = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@""] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSLog(@"任務1完成"); dispatch_group_leave(group); }]; [task1 resume]; // 任務2 dispatch_group_enter(group); NSURLSessionDataTask *task2 = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@""] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSLog(@"任務2完成"); dispatch_group_leave(group); }]; [task2 resume]; // 全部完成 dispatch_group_notify(group, dispatch_get_main_queue(), ^(){ NSLog(@"全部完成"); }); }
任務1和任務2執行完成之後,才會執行全部完成中的任務。
**注意:**在使用時,dispatch_group_enter 和 dispatch_group_leave 需要成對出現,如果 dispatch_group_leave 的呼叫次數多於 dispatch_group_enter 的呼叫次數,程式會 crash。相反,雖然不會發生 crash , 但可能不會達到預期效果。
使用場景是,需要非同步獲取多個圖片封面,所有都獲取完成後,在執行指定任務,程式碼範例如下:
- (void)fetchCovers { dispatch_queue_t queue = dispatch_queue_create("com.demo.xxx", DISPATCH_QUEUE_CONCURRENT); dispatch_group_t group = dispatch_group_create(); for (int i = 0; i < 40; ++i) { dispatch_group_enter(group); dispatch_async(queue, ^{ [self fetchCoverByPHAsset:asset targetSize:CGSizeMake(200, 200) resultHandler:^(UIImage * _Nonnull, NSDictionary * _Nonnull, BOOL) { dispatch_group_leave(group); }]; }); } dispatch_group_notify(group, dispatch_get_main_queue(), ^(){ // 全部完成後 執行指定任務 }); } - (void)fetchCover:(PHAsset *)asset targetSize:(CGSize)targeSize resultHandler:(void (^)(UIImage * _Nonnull, NSDictionary * _Nonnull, BOOL))resultHandler { PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; if (@available(iOS 14.0, *)) { options.version = PHImageRequestOptionsVersionCurrent; } options.networkAccessAllowed = YES; [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:targeSize contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { if (resultHandler) { resultHandler(result, info, [[info objectForKey:PHImageResultIsDegradedKey] boolValue]); } }]; }
這裡有個小 tips : 在使用 requestImageForAsset 獲取圖片時,如果 options 的 deliveryMode 屬性使用預設值,在非同步獲取圖片時,其回撥可能會走2次。解決方案是將其顯示設定為 PHImageRequestOptionsDeliveryModeHighQualityFormat 或 PHImageRequestOptionsDeliveryModeFastFormat。
options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat; // 或 PHImageRequestOptionsDeliveryModeHighQualityFormat
因為獲取圖片封面的回撥可能會走 2 次,從而導致 dispatch_group_leave 呼叫次數多於 dispatch_group_enter 的呼叫次數,因此可能會發生 crash。
void dispatch_group_enter(dispatch_group_t dg) { uint32_t old_bits = os_atomic_sub_orig2o(dg, dg_bits, DISPATCH_GROUP_VALUE_INTERVAL, acquire); uint32_t old_value = old_bits & DISPATCH_GROUP_VALUE_MASK; if (unlikely(old_value == 0)) { _dispatch_retain(dg); // <rdar://problem/22318411> } if (unlikely(old_value == DISPATCH_GROUP_VALUE_MAX)) { DISPATCH_CLIENT_CRASH(old_bits, "Too many nested calls to dispatch_group_enter()"); } }
void dispatch_group_leave(dispatch_group_t dg) { uint64_t new_state, old_state = os_atomic_add_orig2o(dg, dg_state, DISPATCH_GROUP_VALUE_INTERVAL, release); uint32_t old_value = (uint32_t)(old_state & DISPATCH_GROUP_VALUE_MASK); if (unlikely(old_value == DISPATCH_GROUP_VALUE_1)) { old_state += DISPATCH_GROUP_VALUE_INTERVAL; do { new_state = old_state; if ((old_state & DISPATCH_GROUP_VALUE_MASK) == 0) { new_state &= ~DISPATCH_GROUP_HAS_WAITERS; new_state &= ~DISPATCH_GROUP_HAS_NOTIFS; } else { new_state &= ~DISPATCH_GROUP_HAS_NOTIFS; } if (old_state == new_state) break; } while (unlikely(!os_atomic_cmpxchgv2o(dg, dg_state, old_state, new_state, &old_state, relaxed))); return _dispatch_group_wake(dg, old_state, true); } if (unlikely(old_value == 0)) { DISPATCH_CLIENT_CRASH((uintptr_t)old_value, "Unbalanced call to dispatch_group_leave()"); } }
以上就是iOS GCD之dispatch_group_enter和dispatch_group_leave使用的詳細內容,更多關於iOS GCD使用的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45