J'ai un async NSOperation
pour télécharger des données pour plusieurs objets ImageFile
. Comme tout cela se passe de manière asynchrone, j'utilise un groupe de répartition pour suivre les demandes, puis dispatch_group_notify
pour terminer l'opération quand elles sont toutes terminées.Que se passe-t-il avec dispatch_group_enter et dispatch_group_leave?
La question que j'ai est ce qui se passe lorsque l'opération est terminée prématurément, soit par annulation ou par une autre erreur. Le groupe de répartition sera laissé avec dispatch_group_enter
et dispatch_group_leave
de sorte que dispatch_group_notify
ne sera jamais appelé. Est-ce le bloc retenu quelque part par le système qui attend toujours, ou va-t-il être libéré lorsque le NSOperation
sera libéré?
Ou est-ce que mon approche n'est pas idéale, comment pourrais-je faire autrement?
- (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];
});
}];
}