当需要处理资源竞争,可以借用GCD的信号机制
- dispatch_semaphore_create(long value); 创建一个信号资源,参数值value大于等于0,当value = 1表示当前资源是1,value=0表示没有资源
- dispatch_semaphore_wait(dispatch_semaphore_t dsema,dispatch_time_t timeout); 等待(减少)信号资源,如果信号资源<=0,将一直等待知道资源大于0;
- dispatch_semaphore_signal(dispatch_semaphore_t dsema); 产生发送(增加)信号资源,信号源+1
如何理解
举个现实中的例子(洗车),当有5个车主想要去洗车店洗车,但是这个洗车店的只有1个洗车位(相当于信号资源),那么只能先到先洗,等前一辆车洗完,后面的车才能洗,具体的用法是:dispatch_semaphore_create(1),洗车店有一个洗车位,当里面有车在洗车的时候dispatch_semaphore_wait(dispatch_semaphore_t dsema,dispatch_time_t timeout)信号资源-1等待前面的车洗好,假如前面的车洗好了,dispatch_semaphore_signal(dispatch_semaphore_t dsema),这个时候资源+1,后面的车就能洗,当后面的车在洗的时候dispatch_semaphore_wait,资源减1,如此按相对顺序5辆车一辆一辆洗完。
-(void)testDataErrorSetArray
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *mArray = [NSMutableArray array];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//洗车店只有一个洗车位
for (int i = 0; i < 5; i++) {
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//要洗车了信号资源-1
[mArray addObject:[NSNumber numberWithInt:i]];//洗车中
dispatch_semaphore_signal(semaphore);//洗完车发送信号+1
});
}
}
另一个用法是AF中的一个函数,当请求回调block中不知道什么时候返回值,先创建一个资源为0的信号,然后一直等待的信号,当block中返回值成功后信号+1,继续执行下一步。
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
__block NSArray *tasks = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
tasks = dataTasks;
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
tasks = uploadTasks;
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
tasks = downloadTasks;
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return tasks;
}