我在下面有这个逻辑;它们基本上是3个嵌套的调度组块。
group
)将执行3个短异步任务(仅从Web服务下载数据)和1个更长的异步任务:将未同步的记录上载到Web服务,在本地删除已同步的记录,最后下载来自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
一次的任何建议,或者更好的是,如何以更清洁的方式实现此嵌套异步任务完成依赖性(意味着如何等待多个请求完成,然后解雇一些更多,再等一下等等)?
答案 0 :(得分:9)
您每次输入时都会通知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
移出循环。