objective-c - 如果dispatch_group_enter和dispatch_group_leave不匹配会发生什么?

标签 objective-c asynchronous grand-central-dispatch nsoperation

我有一个异步 NSOperation 来下载多个 ImageFile 对象的数据。由于这一切都是异步发生的,我使用调度组来跟踪请求,然后在请求全部完成后使用dispatch_group_notify 来完成操作。

我的问题是,当操作因取消或其他错误而提前结束时会发生什么。调度组将留下不匹配的 dispatch_group_enterdispatch_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.

来自docs for dispatch_group_t :

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/

相关文章:

asynchronous - 异步任务中止时会发生什么?

node.js - 我应该如何在 Node.js 中强制同步?

javascript - 为什么我的变量在函数内部修改后没有改变? - 异步代码引用

swift - GCD 未按 block 顺序执行

ios - 使用 GCD 从核心数据中获取数据会导致 IOS 问题

objective-c - iPad View 出现在侧面

iOS/iPhone 可达性 - 如何仅在互联网丢失/无法使用 Reachability.m/.h 时检查

objective-c - 实现 Objective-C 的根类需要什么?

ios - UICollectionView 单元格在滚动 UICollectionView 时会抖动

ios - 如何确定是否正在等待调度信号量?