1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//子线程下载图片,主线程更新UI
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1
UIImage *overlayImage = [self faceOverlayImageFromImage:_image];
dispatch_async(dispatch_get_main_queue(), ^{ // 2
[self fadeInNewImage:overlayImage]; // 3
});
});
//等待 delayInSeconds 给定的时长,再异步地添加一个 Block 到主线程
NSUInteger count = [[PhotoManager sharedManager] photos].count;
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); // 1
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // 2
if (!count) {
[self.navigationItem setPrompt:@"Add photos with faces to Googlyify them!"];
} else {
[self.navigationItem setPrompt:nil];
}
});
//共享资源线程安全
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[PhotoManager sharedManager];
});
+ (instancetype)sharedManager
{
static PhotoManager *sharedPhotoManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[NSThread sleepForTimeInterval:2];
sharedPhotoManager = [[PhotoManager alloc] init];
NSLog(@"Singleton has memory address at: %@", sharedPhotoManager);
[NSThread sleepForTimeInterval:2];
sharedPhotoManager->_photosArray = [NSMutableArray array];
});
return sharedPhotoManager;
}

//让类本身线程安全
打开 PhotoManager.m,添加如下私有属性到类扩展中:

    1. @interface PhotoManager ()
    1. @property (nonatomic,strong,readonly) NSMutableArray *photosArray;
    1. @property (nonatomic, strong) dispatch_queue_t concurrentPhotoQueue; ///< Add this
    1. @end

找到 addPhoto: 并用下面的实现替换它:

1
2
3
4
5
6
7
8
9
10
11
1. - (void)addPhoto:(Photo *)photo
2. {
3. if (photo) { // 1
4. dispatch_barrier_async(self.concurrentPhotoQueue, ^{ // 2
5. [_photosArray addObject:photo]; // 3
6. dispatch_async(dispatch_get_main_queue(), ^{ // 4
7. [self postContentAddedNotification];
8. });
9. });
10. }
11. }

####你新写的函数是这样工作的:

  1. 在执行下面所有的工作前检查是否有合法的相片。
  2. 添加写操作到你的自定义队列。当临界区在稍后执行时,这将是你队列中唯一执行的条目。
  3. 这是添加对象到数组的实际代码。由于它是一个障碍 Block ,这个 Block 永远不会同时和其它 Block 一起在 concurrentPhotoQueue 中执行。
  4. 最后你发送一个通知说明完成了添加图片。这个通知将在主线程被发送因为它将会做一些 UI 工作,所以在此为了通知,你异步地调度另一个任务到主线程。
    这就处理了写操作,但你还需要实现 photos 读方法并实例化 concurrentPhotoQueue 。