1

我有一个异步NSOperation下载多个ImageFile对象的数据。由于这一切都是异步发生的,我使用一个调度组跟踪请求,然后在完成操作后完成操作。不匹配的dispatch_group_enter和dispatch_group_leave会发生什么?

我的问题是当操作过早结束时发生的情况,无论是通过取消还是通过其他错误。调度组将保留无与伦比的dispatch_group_enterdispatch_group_leave,因此不会调用dispatch_group_notify。系统永远在等待系统保留的区块吗,还是在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]; 
     }); 
    }]; 
} 

回答

2

docs for dispatch_group_enter()

调用这个函数必须以dispatch_group_leave通话平衡。

docs for dispatch_group_t

调度组跟踪的很多块是如何优秀,和GCD保留组,直到其所有相关的块完整的执行。

它谈论优秀块,但它的真正含义是无与伦比的呼吁dispatch_group_enter()

所以,你的问题的答案是关于调度组对象有效泄漏的问题。传递给dispatch_group_notify()的块对象及其强引用的任何对象也会泄漏。在你的情况下,这包括self

对于你的问题,你的方法是否“理想”的答案是:不,这不是理想的。 GCD的设计合同甚至没有这个效力。您需要必须将所有致电dispatch_group_enter()的呼叫与致电dispatch_group_leave()

如果您想以某种方式区分成功与失败或正常完成与取消,则应设置可用于通知块的某些状态,然后对通知块进行编码以查阅该状态以决定要执行的操作。

然而就你而言,你不能调用dispatch_group_leave()的代码路径只是做通知块会做的同样的事情。所以我甚至不知道为什么你不只是打电话dispatch_group_leave()而不是在这些情况下打电话[self completeOperation]

相关问题