Reputation: 2522
I know that dispatch_group_leave
calls need to be balanced with dispatch_group_enter
.
Here is the block of code where my crash is happening (randomly, not always)
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self getVibrationHistorySuccess:^(NSArray<VibrationPointDTO *> *vibrationPoints) {
self.vibrationPoints = vibrationPoints;
dispatch_group_leave(group);
} failure:^(NSError *error) {
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self getTemperatureHistorySuccess:^(NSArray<TemperatureSetDTO *> *sets) {
self.temperatureSets = sets;
dispatch_group_leave(group);
} failure:^(NSError *error) {
dispatch_group_leave(group);
}];
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
[self showLoading:NO];
[self updateChartWithVibrationHistory:self.vibrationPoints temperatureSets:self.temperatureSets];
});
There are 2 enters, and 2 exits (on each of the closures, it is only possible to either be successful or failed, so only one of the 2 happen)
So why is my code crashing like this? How can I trouble shoot this?
The only other thing that comes to mind, is that multiple instances of this object do get used at the same time. Is it possible that the same group is being used by those different instances? Would there be a way to make sure the group itself is unique between those instances? Otherwise I can't think of why this is happening.
PS: I added swift tag as well to get more attention into the question as the same problem could happen no matter the language
EDIT 1
Adding missing methods based on comment received:
This is getTemperatureHistorySuccess
which is the one that crashed
-(void)getTemperatureHistorySuccess:(void (^)(NSArray<TemperatureSetDTO*> *sets))success
failure:(void(^)(NSError *error))failure{
NSMutableArray *sets = [NSMutableArray new];
dispatch_group_t group = dispatch_group_create();
for (TemperatureSummaryNew *sensor in self.regionPCA.temperatureSensors) {
dispatch_group_enter(group);
[TemperatureSensorsService getHistory:sensor.temperatureSensorID startDate:self.startDate stopDate:self.stopDate interval:self.currentInterval success:^(NSArray<TemperaturePointDTO *> *result) {
TemperatureSetDTO *set = [TemperatureSetDTO new];
set.points = result;
[sets addObject:set];
dispatch_group_leave(group);
} failure:^(NSError *error) {
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
success(sets);
});
}
and here is the getHistory
that gets called in the loop:
+ (void) getHistory:(int)sensorID
startDate:(NSDate*)startDate
stopDate:(NSDate*)stopDate
interval:(HistoryInterval)interval
success:(void (^)(NSArray<TemperaturePointDTO*>* result))success
failure:(void(^)(NSError *error))failure{
ApiManager *api = [ApiManager sharedManager];
NSDictionary *params = @{
@"TemperatureSensorID" : [Converter toDictionaryValueFromInt:sensorID],
@"StartDate" : [Converter toDictionaryValueGMTFromDate:startDate],
@"StopDate" : [Converter toDictionaryValueGMTFromDate:stopDate],
@"Interval" : [Converter toDictionaryValueFromHistoryInterval:interval]};
[api POST:kApiTemperatureSensorsGetHistory parameters:params progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
if (success) {
NSArray* res = [Converter fromDictionaryValueToTemperaturePointDTOArray:responseObject];
success(res);
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if (failure) {
failure(error);
}
}];
}
Here is getVibrationHistorySuccess
-(void)getVibrationHistorySuccess:(void (^)(NSArray<VibrationPointDTO *> *vibrationPoints))success
failure:(void(^)(NSError *error))failure{
__block NSArray<VibrationPointDTO *> *points;
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self getDistanceHistorySuccess:^{
dispatch_group_leave(group);
} failure:^(NSError *error) {
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[VibrationSensorsService getHistory:self.regionPCA.regionID startDate:self.startDate stopDate:self.stopDate interval:self.currentInterval success:^(NSArray<VibrationPointDTO *> *result) {
points = result;
dispatch_group_leave(group);
} failure:^(NSError *error) {
dispatch_group_leave(group);
failure(error);
}];
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
success(points);
});
}
VibrationSensorsService getHistory
is exactly the same as the previous one, but pointing to a different endpoint
Upvotes: 2
Views: 710
Reputation: 385590
Here's the last part of getVibrationHistorySuccess:failure:
, copied from your question:
[VibrationSensorsService getHistory:self.regionPCA.regionID startDate:self.startDate stopDate:self.stopDate interval:self.currentInterval success:^(NSArray<VibrationPointDTO *> *result) { points = result; dispatch_group_leave(group); } failure:^(NSError *error) { dispatch_group_leave(group); failure(error); }]; dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{ success(points); });
This code always calls success(points)
. In addition, it sometimes calls failure(error)
. That means both the success
and failure
blocks may be executed.
Upvotes: 1