I have recently modified an existing project and modified some methods from returning a value (BOOL) to call a completion block. I followed this very good answer:
https://stackoverflow.com/a/16324193/942165
Now I have my method that calls the completion block, it is working great, but I am afraid it can unpredictably fail for not being thread safe.
I have my declaration of the block:
typedef void(^myCompletion)(id, BOOL);
Following is my method with completion handler:
-(void)myMethodThatTakesAnArgument:(id)object completionHandler:(myCompletion)completionblock {
//do things that are allowed in the main thread:
//...
//...
dispatch_queue_t backgroundQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(backgroundQueue, ^{
[self doWorkButReturnImmediately];
BOOL workIsNotFinished = [self isJobFinished];
NSDate *processingStart = [NSDate date];
NSTimeInterval timeElapsed = 0.0;
while (workIsNotFinished && timeElapsed < 15.0) {
[NSThread sleepForTimeInterval:1.0];
timeElapsed = [[NSDate date] timeIntervalSinceDate:processingStart];
workIsNotFinished = [self isJobFinished];
}
dispatch_async(dispatch_get_main_queue(), ^{
// Return Result
completionblock(object,YES);
});
});
}
Following is my caller method:
- (void)callerMethod {
NSArray *arrayOfObjects = [self prepareArrayOfObjects];
NSMutableArray *unprocessedObjects = [arrayOfObjects mutableCopy];
for (NSString *string in arrayOfObjects) {
[self myMethod:string completionblock:^(id obj, BOOL success) {
[unprocessedObjects removeObject:string];
if(success){
// do something with obj
NSLog(@"success");
}
if ([unprocessedObjects count] == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
// Everything is done, act accordingly.
});
}
}
}
}
I suspect this scenario can somehow fail and I am thinking of adding some thread safety code. I am not a lot expert of the subject, but it appears to me that probably, @synchronized could be the way to go. So I would like to embed the code of the called method in some @synchronized statements, but I am not sure if this is necessary in this case, and, if it is, I am not sure on where to specifically put the statements, I think probably in the part that is dispatched in a background queue. In the code, I have included a simple object that is passed back in the completion handler that could act as the object to pass to @synchronized. Any help is greatly appreciated. Thanks