Jan
Jan

Reputation: 2522

How to troubleshoot a dispatch_group_leave crash

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?

enter image description here

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

Answers (1)

rob mayoff
rob mayoff

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

Related Questions