当两个单独的 NSFetchRequest 都完成时采取行动
Posted
技术标签:
【中文标题】当两个单独的 NSFetchRequest 都完成时采取行动【英文标题】:Take action when two separate NSFetchRequests have both completed 【发布时间】:2013-11-12 02:25:16 【问题描述】:我正在使用带有 Core Data 的远程数据库,当我执行以下获取请求时,根据 Internet 连接,可能需要一些时间。我想监控这两个请求,当它们完成时——无论成功还是失败——我想触发另一种方法。
FetchRequest 1:
[self.managedObjectContext executeFetchRequest:fetchRequest1 onSuccess:^(NSArray *results)
//Succcess
[self.refreshControl endRefreshing];
onFailure:^(NSError *error)
[self.refreshControl endRefreshing];
];
FetchRequest 2:
[self.managedObjectContext executeFetchRequest:fetchRequest2 onSuccess:^(NSArray *results)
//Succcess
[self.refreshControl endRefreshing];
onFailure:^(NSError *error)
[self.refreshControl endRefreshing];
];
我想等到获取请求 1 和 2 都完成后再调用另一个方法。
我可以使用NSOperationQueue
来监控这两个块吗?如果没有,知道两个块何时完成的最佳方法是什么?
【问题讨论】:
查看这个帖子***.com/questions/11909629/… 【参考方案1】:当您有具有依赖关系的异步任务时,您有两种选择:
代码更改最少的最简单解决方案是使用信号量:
// create a semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// initiate two requests (signaling when done)
[self.managedObjectContext executeFetchRequest:fetchRequest1 onSuccess:^(NSArray *results)
[self.refreshControl endRefreshing];
dispatch_semaphore_signal(semaphore);
onFailure:^(NSError *error)
[self.refreshControl endRefreshing];
dispatch_semaphore_signal(semaphore);
];
[self.managedObjectContext executeFetchRequest:fetchRequest2 onSuccess:^(NSArray *results)
[self.refreshControl endRefreshing];
dispatch_semaphore_signal(semaphore);
onFailure:^(NSError *error)
[self.refreshControl endRefreshing];
dispatch_semaphore_signal(semaphore);
];
// now create task to to wait for these two to finish signal the semaphore
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
// wait for the two signals from the two fetches to be sent
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// now do whatever you want when those two requests finish
// if you need to do any UI update or do any synchronizing with the main queue, just dispatch this to the main queue
dispatch_async(dispatch_get_main_queue(), ^
NSLog(@"all done");
);
);
这种方法可能最简单,但也存在各种限制。例如,这将占用一个等待其他两个发送信号的工作线程,因此您必须确信您没有太多的这些请求集合同时进行。您还必须确信这些请求将调用 onSuccess
或 onFailure
,但绝不会同时调用两者,并且始终调用一个。这也并没有真正提供取消机会或自己限制并发程度的能力。但是您可以通过最少的代码更改来完成上述操作。
第二种方法是将您的异步请求替换为同步请求,然后您可以使用NSOperation
标准addDependency
逻辑:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^
// completion operation
];
NSOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^
// do fetch1 _synchronously_
];
[queue addOperation:operation1];
NSOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^
// do fetch2 _synchronously_
];
[queue addOperation:operation2];
[completionOperation addDependencies:@[operation1, operation2]];
[queue addOperation:completionOperation];
这种方法要求您的同步提取是线程安全的。我对你使用的这个 API 不熟悉,所以我不能说。
1234563isFinished
直到异步操作完成(也可能调用你自己的 onSuccess
和 onFailure
块)。一旦你这样做了,你就可以使用setDependency
功能(如前一点所示)使你的第三个操作依赖于其他两个完成。如需更多信息,请参阅并发编程指南的Configuring Operations for Concurrent Execution 部分。
我希望我能提供一个更明确的答案,但我对您的并发托管上下文库所包含的选项/约束不够熟悉。
【讨论】:
感谢您的详细解释!以上是关于当两个单独的 NSFetchRequest 都完成时采取行动的主要内容,如果未能解决你的问题,请参考以下文章
当查询包含撇号时,NSFetchRequest 会触发 NSInvalidArgumentException