我有一个异步 NSOperation
来下载多个 ImageFile
对象的数据。由于这一切都是异步发生的,我使用调度组来跟踪请求,然后在请求全部完成后使用dispatch_group_notify 来完成操作。
我的问题是,当操作因取消或其他错误而提前结束时会发生什么。调度组将留下不匹配的 dispatch_group_enter
和 dispatch_group_leave
,因此永远不会调用 dispatch_group_notify
。它是被系统保留在某个地方永远等待的 block ,还是会在 NSOperation
被释放时被释放?
或者我的方法不理想,我还应该怎么做?
- (void)main
{
if (self.cancelled) {
[self completeOperation];
return;
}
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.persistentStoreCoordinator = self.persistentStoreCoordinator;
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[context performBlock:^{
NSFetchRequest *request = [ImageFile fetchRequest];
request.predicate = ....
request.sortDescriptors = ...
NSError *error;
NSArray *imageFiles = [context executeFetchRequest:request error:&error];
if (!imageFiles) {
// Error handling...
[self completeOperation];
return;
}
dispatch_group_t group = dispatch_group_create();
for (ImageFile *imageFile in imageFiles) {
dispatch_group_enter(group);
@autoreleasepool {
[self.webService requestImageWithId:imageFile.id completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (self.cancelled) {
[self completeOperation];
return;
}
[context performBlock:^{
if (data && !error) {
imageFile.data = data;
NSError *error;
if (![context save:&error]) {
// Error handling...
[self completeOperation];
return;
}
}
dispatch_group_leave(group);
}];
}];
}
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[self completeOperation];
});
}];
}
最佳答案
来自docs for dispatch_group_enter()
:
A call to this function must be balanced with a call to
dispatch_group_leave
.
The dispatch group keeps track of how many blocks are outstanding, and GCD retains the group until all its associated blocks complete execution.
它谈论的是未完成的 block ,但它的真正含义是对 dispatch_group_enter()
的无与伦比的调用.
因此,您关于所发生情况的问题的答案是调度组对象实际上泄漏了。传递给 dispatch_group_notify()
的 block 对象并且它具有强引用的任何对象也会泄漏。就您而言,这包括 self
.
对于您的方法是否“理想”的问题,答案是:不,这并不理想。甚至GCD的设计契约(Contract)都无效。您必须平衡对 dispatch_group_enter()
的所有调用调用dispatch_group_leave()
.
如果您想以某种方式区分成功和失败或正常完成和取消,您应该设置一些可供通知 block 使用的状态,然后对通知 block 进行编码以查阅该状态来决定要做什么。
但是,在您的情况下,您无法调用 dispatch_group_leave()
的代码路径只需执行与通知 block 相同的操作即可。所以我什至不确定你为什么不直接打电话 dispatch_group_leave()
而不是打电话 [self completeOperation]
在这些情况下。
关于objective-c - 如果dispatch_group_enter和dispatch_group_leave不匹配会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42239369/