dispatch_group_notify 被调用的次数与 dispatch_group_leave 在嵌套块中的调用次数相同
dispatch_group_notify being called as many times as dispatch_group_leave is called in nested blocks
我有下面这个逻辑;它们基本上是 3 个嵌套的调度组块。
- 第一组(
group
)将执行 3 个简短的异步任务(仅从 Web 服务下载数据)和 1 个较长的异步任务:将未同步的记录上传到 Web 服务,在本地删除同步的记录,然后最后从网络服务下载记录(首先是一个包含 ID 和基本信息的数组,然后是这些记录中的每一个)。
- 第二组 (
saveGroup
) 是较长任务的一部分。它将等到对 Web 服务的所有未同步记录请求完成。
- 第三个 (
downloadGroup
) 将等到对服务的所有这些单个记录下载请求都完成。
一切顺利,直到第三个调度组。如您所见,我获取了服务器上记录的 ID 和基本信息,遍历数组并使用 downloadGroup 调用 dispatch_group_enter,然后触发 HTTP 请求。 dispatch_group_leave
在请求完成时被调用。我可以看到每个请求都调用了 dispatch_group_leave
,最后 dispatch_group_notify
被调用了很多次。
-(void) doTheSync {
dispatch_group_t group = dispatch_group_create();
[self syncFirstDataWithGroup: group];
[self syncSecondDataWithGroup: group];
[self syncThirdDataWithGroup: group];
[self syncRecordsWithExternalGroup: group];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Finished all the sync");
});
}
-(void) syncRecordsWithExternalGroup: (dispatch_group_t) externalGroup {
dispatch_group_enter(externalGroup);
NSError* error = nil;
ConfigureDataModelHandler* configDataHandler = [ConfigureDataModelHandler sharedCoredata];
WebserviceLib* RESTClient = [WebserviceLib sharedInstance];
//get all unsynced records (f
NSArray* recordsUnsynced = [configDataHandler getAllRecordsWithSynced: NO ignoreDelete: YES withError: &error];
if (!error) {
//upload them to the BE (and mark as synced if succeed
dispatch_group_t saveGroup = dispatch_group_create();
//get full record dictionary, save and mark as synced
for (CMrecord* record in recordsUnsynced) {
NSDictionary* recordDict = [configDataHandler exportToDictionary: record.recordID.integerValue];
dispatch_group_enter(saveGroup);
[RESTClient saverecord: recordDict onComplete:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Saved unsynced record (%@) to BE", record.recordID);
//mark as synced
[configDataHandler markrecordAsSynced: record.recordID.integerValue];
dispatch_group_leave(saveGroup);
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error saving unsynced record to BE %@", error);
dispatch_group_leave(saveGroup);
}];
}
//** NOTIFY FINISH SAVING **
dispatch_group_notify(saveGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finished saving all unsynced records to BE");
//delete all synced records
//TODO: Check if this makes sense. Probably better to not delete anything until we got the full record from the BE...
[configDataHandler deleteRecordsSynced];
//download small records from BE
NSString* agentNationalID = [self.coreData getLoginStatus].nationalID;
[RESTClient getRecordsForAgent: agentNationalID onComplete:^(NSInteger completeCode, NSArray *responseArray) {
NSLog(@"Success getting the records %@", responseArray);
if (completeCode == 200) {
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSDictionary* shortDict in responseArray) {
dispatch_group_enter(downloadGroup);
//download full records from BE
[RESTClient getRecordByCodeAndTimestamp: shortDict onComplete:^(NSInteger completeCode, NSDictionary *responseDictionary) {
NSLog(@"Success Downloading record");
dispatch_group_leave(downloadGroup);
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error downloading record %@", shortDict);
dispatch_group_leave(downloadGroup);
}];
//** NOTIFY FINISH DOWNLOADING **
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finished downloading all the records");
//This is CRASHING because this block is being called as many times as the dispatch_group_leave(downloadGroup) is called
dispatch_group_leave(externalGroup);
});
}
} else {
NSLog(@"Error getting the records for Agent %@, with Code %li", @"AGENT ID", (long)completeCode);
}
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error getting the records for Agent %@, %@", @"AGENT ID", operation.response);
}];
});
}
}
我在其他部分使用具有正常行为(创建、进入、进入、离开、离开、通知)的调度组,所以我不明白这里发生了什么。它与嵌套块有关吗?有关如何在完成时仅调用一次 dispatch_group_notify
的任何建议,或者更好的是,如何以更清晰的方式实现此嵌套异步任务完成依赖性(意味着如何等待多个请求完成,然后触发一些更多并再次等待等等)?
您每次进入时都会通知 downloadGroup
组
for (NSDictionary* shortDict in responseArray) {
dispatch_group_enter(downloadGroup);
//download full records from BE
[RESTClient getRecordByCodeAndTimestamp: shortDict onComplete:^(NSInteger completeCode, NSDictionary *responseDictionary) {
NSLog(@"Success Downloading record");
dispatch_group_leave(downloadGroup);
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error downloading record %@", shortDict);
dispatch_group_leave(downloadGroup);
}];
// BUG IS HERE
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finished downloading all the records");
dispatch_group_leave(externalGroup);
});
}
// dispatch_group_notify should be moved HERE
你应该只通知组一次,将 dispatch_group_notify
移出循环。
我有下面这个逻辑;它们基本上是 3 个嵌套的调度组块。
- 第一组(
group
)将执行 3 个简短的异步任务(仅从 Web 服务下载数据)和 1 个较长的异步任务:将未同步的记录上传到 Web 服务,在本地删除同步的记录,然后最后从网络服务下载记录(首先是一个包含 ID 和基本信息的数组,然后是这些记录中的每一个)。 - 第二组 (
saveGroup
) 是较长任务的一部分。它将等到对 Web 服务的所有未同步记录请求完成。 - 第三个 (
downloadGroup
) 将等到对服务的所有这些单个记录下载请求都完成。
一切顺利,直到第三个调度组。如您所见,我获取了服务器上记录的 ID 和基本信息,遍历数组并使用 downloadGroup 调用 dispatch_group_enter,然后触发 HTTP 请求。 dispatch_group_leave
在请求完成时被调用。我可以看到每个请求都调用了 dispatch_group_leave
,最后 dispatch_group_notify
被调用了很多次。
-(void) doTheSync {
dispatch_group_t group = dispatch_group_create();
[self syncFirstDataWithGroup: group];
[self syncSecondDataWithGroup: group];
[self syncThirdDataWithGroup: group];
[self syncRecordsWithExternalGroup: group];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Finished all the sync");
});
}
-(void) syncRecordsWithExternalGroup: (dispatch_group_t) externalGroup {
dispatch_group_enter(externalGroup);
NSError* error = nil;
ConfigureDataModelHandler* configDataHandler = [ConfigureDataModelHandler sharedCoredata];
WebserviceLib* RESTClient = [WebserviceLib sharedInstance];
//get all unsynced records (f
NSArray* recordsUnsynced = [configDataHandler getAllRecordsWithSynced: NO ignoreDelete: YES withError: &error];
if (!error) {
//upload them to the BE (and mark as synced if succeed
dispatch_group_t saveGroup = dispatch_group_create();
//get full record dictionary, save and mark as synced
for (CMrecord* record in recordsUnsynced) {
NSDictionary* recordDict = [configDataHandler exportToDictionary: record.recordID.integerValue];
dispatch_group_enter(saveGroup);
[RESTClient saverecord: recordDict onComplete:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Saved unsynced record (%@) to BE", record.recordID);
//mark as synced
[configDataHandler markrecordAsSynced: record.recordID.integerValue];
dispatch_group_leave(saveGroup);
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error saving unsynced record to BE %@", error);
dispatch_group_leave(saveGroup);
}];
}
//** NOTIFY FINISH SAVING **
dispatch_group_notify(saveGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finished saving all unsynced records to BE");
//delete all synced records
//TODO: Check if this makes sense. Probably better to not delete anything until we got the full record from the BE...
[configDataHandler deleteRecordsSynced];
//download small records from BE
NSString* agentNationalID = [self.coreData getLoginStatus].nationalID;
[RESTClient getRecordsForAgent: agentNationalID onComplete:^(NSInteger completeCode, NSArray *responseArray) {
NSLog(@"Success getting the records %@", responseArray);
if (completeCode == 200) {
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSDictionary* shortDict in responseArray) {
dispatch_group_enter(downloadGroup);
//download full records from BE
[RESTClient getRecordByCodeAndTimestamp: shortDict onComplete:^(NSInteger completeCode, NSDictionary *responseDictionary) {
NSLog(@"Success Downloading record");
dispatch_group_leave(downloadGroup);
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error downloading record %@", shortDict);
dispatch_group_leave(downloadGroup);
}];
//** NOTIFY FINISH DOWNLOADING **
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finished downloading all the records");
//This is CRASHING because this block is being called as many times as the dispatch_group_leave(downloadGroup) is called
dispatch_group_leave(externalGroup);
});
}
} else {
NSLog(@"Error getting the records for Agent %@, with Code %li", @"AGENT ID", (long)completeCode);
}
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error getting the records for Agent %@, %@", @"AGENT ID", operation.response);
}];
});
}
}
我在其他部分使用具有正常行为(创建、进入、进入、离开、离开、通知)的调度组,所以我不明白这里发生了什么。它与嵌套块有关吗?有关如何在完成时仅调用一次 dispatch_group_notify
的任何建议,或者更好的是,如何以更清晰的方式实现此嵌套异步任务完成依赖性(意味着如何等待多个请求完成,然后触发一些更多并再次等待等等)?
您每次进入时都会通知 downloadGroup
组
for (NSDictionary* shortDict in responseArray) {
dispatch_group_enter(downloadGroup);
//download full records from BE
[RESTClient getRecordByCodeAndTimestamp: shortDict onComplete:^(NSInteger completeCode, NSDictionary *responseDictionary) {
NSLog(@"Success Downloading record");
dispatch_group_leave(downloadGroup);
} onError:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error downloading record %@", shortDict);
dispatch_group_leave(downloadGroup);
}];
// BUG IS HERE
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finished downloading all the records");
dispatch_group_leave(externalGroup);
});
}
// dispatch_group_notify should be moved HERE
你应该只通知组一次,将 dispatch_group_notify
移出循环。