Barrier主要用於在多個異步操作完成之後,統一對非線程安全的對象進行更新, 如NSMutableString/NSMutableArray…
- Barrier的工作原理
將所有之前添加的異步執行完成之後,在同一個線程中,順序執行 block 中的代碼
接下來我們看一下它是如何實現的 ?
- 首先創建一個併發隊列
_queue = dispatch_queue_create("ejParadise", DISPATCH_QUEUE_CONCURRENT);
注意: 必須是自定義的, 不能使用 _queue = dispatch_get_global_queue(0, 0); 否則執行效果沒有影響
- 準備工作
- (NSMutableArray *)photoList {
if (_photoList == nil) {
_photoList = [NSMutableArray array];
}
return _photoList;
}
- 下載圖片
// 開啓多個任務,分別下載圖片
- (void)loadPictures:(int)index {
dispatch_async(_queue, ^{
// 模擬延時
[NSThread sleepForTimeInterval:1.0];
// 模擬從網絡下載圖片
NSString *fileName = [NSString stringWithFormat:@"%02d.jpg", index % 10 + 1];
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
UIImage *image = [UIImage imageWithContentsOfFile:path];
// 將圖像添加到數組
// NSMutableArray 不是線程安全的,如果同一個時間點,多個線程項數組添加,有可能會出現崩潰
// 要解決這個問題,需要一個特殊的函數
// 將所有之前添加的異步執行完成之後,在同一個線程中,順序執行 block 中的代碼
dispatch_barrier_async(_queue, ^{
NSLog(@"添加圖片 %@ %@", fileName, [NSThread currentThread]);
[self.photoList addObject:image];
});
// [self.photoList addObject:image];
NSLog(@"下載完成 %@ %@", fileName, [NSThread currentThread]);
});
}
- 調用下載
for (int i = 0; i < 10; ++i) {
[self loadPictures:i];
}
這樣就可以確保圖片完成加載後才執行Block裏面的內容添加圖片