Thread safety in method with asynchronous operations - ios

I have this method
- (void) checkIfShouldSendReadingsToServerAsync
{
// Check if I want to send the data
// All other threads should wait hear until I signal them to continue
if (!self.lastSendRequestToServerDateTime ||
([[NSDate date] timeIntervalSinceDate:self.lastSendRequestToServerDateTime]/60.0) > intervalBetweenRequestsToServerInMinutes.doubleValue)
{
// Read data from the SQLite database asynchronous and a completion block
// This call uses a NSOperationQueue block
[self.sqliteStore readingsToSendToServer:^(NSArray *readingsArray)
{
// Loaded the values, now check if I should send them
if (readingsArray &&
readingsArray.count > 0)
{
// Convert array of objects to JSON
NSString* json = [self.sqliteStore readingsArrayToJSON:readingsArray];
// Send the JSON to the server using NSURLSession
[[WEEServiceRepository sharedInstance] sendJSONReadings:json withCompletionHandler:^(NSError *error, NSURLResponse *response)
{
// REST POST call ended, check the status code
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger statusCode = httpResponse.statusCode;
self.lastSendRequestToServerDateTime = [NSDate date];
switch (statusCode)
{
case 200:
case 201:
case 204:
{
// This call uses a NSOperationQueue block
[self.sqliteStore updateReadingsWithSentToServerYes:readingsArray andCompletionBlock:^(BOOL succeed)
{
// Here allow all other threads or the same thread to enter
}];
break;
}
default:
{
// Or here signal to continue
}
}
}];
}
}];
}
}
I want this whole method to be thread safe, until the service call returns and signals that it is OK for other threads to continue it should keep them in line.
This code will run when the application is in the foreground but in the background as well.
I tried semaphores but for a reason after a while I found that it stopped in the background, deadlock maybe? But it shouldn't! I don't really want to use #synchronized, or am I wrong and go ahead and try? Maybe just use NSLock or NSRecursiveLock?
I try to find the most appropriate way to lock and unlock the section of code, especially when using asynchronous methods.

I ensured thread safety when you have to deal with a series of dependent asynchronous operation with the help of this example, overriding from NSOperation and implementing the properties isExecuting, isFinished and the start method can give you control when the queue will release the operation and proceed to the next one with in my case setting the NSOperationQueue.maxConcurrentOperationCount to 1.

Related

How to improve this objective-c code (blocks, RestKit, async, threads)

I'm maintaining an old game code (>5 yrs old) and switched developers hands a few times. Game doesn't has a dedicated player base (an early casino gambling game).
RestKit is used for API calls.
Please find comments: // SECTION_1 // SECTION_2 in the code below.
// SECTION_1 : can make it async, use blocking logic. What are the some immediate risks related to introducing threading bugs?
// SECTION_2 : Need to fix a bug bug in previous logic here. Bug: self.fetchAllPlayersCallback gets invoked before waiting for self.fetchAllPlayersFriendCheckCallback. For correct UI update, I would need to combine self.fetchAllPlayersFriendCheckCallback and self.fetchAllPlayersCallback.
Code:
/* getAllPlayersInGame:(NSString *)gameId
* Fetch players for a game in progress, update UI, invoke fetchAllPlayersCallback
* Also detect if players are friends. Prepare friends set and invoke fetchAllPlayersFriendCheckCallback.
*/
- (void)getAllPlayersInGame:(NSString *)gameId
{
self.fetchAllPlayersInProgress = YES;
self.fetchAllPlayersError = nil;
[SocialManager getPlayersAndProfilesForGameId:gameId userId:[UserManager getActiveUser] completion:^(NSError *error, SocialUsers *users, SocialProfiles *profiles)
{
if (error) {
self.fetchAllPlayersError = error;
// TODO: show ui error alert
return;
}
__block NSUInteger totalusers = [self.lobby.players count];
__block BOOL isAllPlayersFriends = YES;
__block NSMutableSet *friendsInGame = [[NSMutableSet alloc] init]
// SECTION_1
// separate lightweight call to server per player.
// server implementation limitation doesn't allow sending bulk requests.
for (SocialUser *player in self.lobby.players) {
NSString *playerId = player.playerID;
[SocialManager isUser:userId friendsWithPlayer:playerId completionBlock:^(PlayHistory *playHistory, NSError *error) {
totalusers--;
if (!error) {
isAllPlayersFriends &= playHistory.isFriend;
if (playHistory.isFriend)
{
// TODO: Add to friendsInGame
// TODO: save other details (game history, etc for ui population)
}
} else {
self.fetchAllPlayersFriendCheckCallback(isAllPlayersFriends, friendsInGame, error);
return;
}
if (0 == totalusers) {
fetchAllPlayersFriendCheckCallback(isAllPlayersFriends, friendsInGame, error);
}
}];
};
// SECTION_2
// TODO: update data model
// TODO: UI update view
self.fetchAllPlayersInProgress = NO;
if (self.fetchAllPlayersCallback)
{
self.fetchAllPlayersCallback();
self.fetchAllPlayersCallback = nil;
}
}];
}
There are a few approaches:
If you have a bunch of asynchronous requests that can happen concurrently with respect to each other and you want to trigger some other task when they're done, you might use Grand Central Dispatch (GCD) dispatch groups.
For example, rather than counting down totalUsers, the standard GCD approach is to use a dispatch group. Dispatch groups can trigger some block that will be called when a bunch of asynchronous calls are done. So you:
Create a group before you start your loop;
Enter your group before you start asynchronous call;
Leave your group in the asynchronous call's completion handler;
Specify a dispatch_group_notify block that will be called when each "enter" is matched with a "leave".
Thus, something like:
dispatch_group_t group = dispatch_group_create();
for (SocialUser *player in self.lobby.players) {
dispatch_group_enter(group);
[SocialManager ...: ^{
...
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
fetchAllPlayersFriendCheckCallback(isAllPlayersFriends, friendsInGame, error);
self.fetchAllPlayersInProgress = NO;
if (self.fetchAllPlayersCallback) {
self.fetchAllPlayersCallback();
self.fetchAllPlayersCallback = nil;
}
});
Now, this presumes that this call is asynchronous but that they can run concurrently with respect to each other.
Now, if these asynchronous calls need to be called consecutively (rather than concurrently), then you might wrap them in asynchronous NSOperation or something like that, which assures that even if they're running asynchronously with respect to the main queue, they'll run consecutively with respect to each other. And if you use that approach, rather than using a dispatch group for the completion operations, you would use NSOperation dependencies. For example, here's a trivial example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSOperation *completion = [NSBlockOperation blockOperationWithBlock:^{
// stuff to be done when everything else is done
}];
for (Foo *foo in self.foobars) {
NSOperation *operation = [SocialManager operationForSomeTask:...];
[completionOperation addDependency:operation];
[queue addOperation:operation];
}
[[NSOperationQueue mainQueue] addOperation:completionOperation];
But all of this assumes that you're refactored your social manager to wrap its asynchronous requests in custom asynchronous NSOperation subclass. It's not rocket science, but if you haven't done that before, you might want to gain familiarity with creating them before you tackle refactoring your existing code to do so.
Another permutation of the previous point is that rather than refactoring your code to use custom asynchronous NSOperation subclasses, you could consider a framework like PromiseKit. It still requires you to refactor your code, but it has patterns that let you wrap your asynchronous task in "promises" (aka "futures"). I only mention it for the take of completeness. But you might not want to throw a whole new framework in this mix.
Bottom line, there's simply not enough here to diagnose this. But dispatch groups or custom asynchronous NSOperation subclasses with completion operations.
But the comment in that code that says "use blocking logic" is generally not a good idea. You should never block and with well designed code, it's completely unnecessary.

iOS Stop block execution from progressing until block has finished

I have a method in an iOS app that is supposed to return a bool value depending upon whether or not a web call succeeds.
The web call is structured in a way such that it takes a block as a callback parameter and that callback is called when the web call has a result. Based on that result my method needs to return a True/False value.
So, I need to stop execution from progressing any further without first having a result to return.
I am trying to achieve this via semaphores, after looking at some examples that others have shared, but the callback is never called, if I remove the semaphore then the callback is always called.
What am I missing here?
+ (BOOL)getUserInformation {
__block BOOL flag = false;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[[WebServicesManager sharedManager] getUserInformationWithCallback:^(NSInteger statusCode, NSString *response, NSDictionary *responseHeaders, id obj, NSError *error) {
if (error) {
//Handle error case and perform appropriate cleanup actions.
}
else
{
//Save user information
flag = true;
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return flag;
}
I put a break point on if(error) to check if the callback gets called, it doesnt, unless I remove the semaphore.
I could give this method its own callback block or I could give the containing class a delegate and achieve what I need but I would really like to make this approach work.
The WebServicesManager is probably dispatching it's block on the same thread the semaphore is waiting on.
As #Rob is correctly mentioning in the comments, this is most likely not a good idea to do on the main thread; rather make use of the asynchronous model and not block the main thread for possibly minutes until the connection may time out under certain circumstances, freezing your UI.
You are undoubtedly deadlocking because you're using semaphore on same thread to which the web services manager (or the API that that is using) dispatches its completion handler.
If you want a rendition that avoids the deadlock scenario, but also avoids the pitfalls of blocking the main thread, you can do something like:
+ (void)getUserInformation:(nonnull void (^)(BOOL))completionHandler {
[[WebServicesManager sharedManager] getUserInformationWithCallback:^(NSInteger statusCode, NSString *response, NSDictionary *responseHeaders, id obj, NSError *error) {
if (error) {
completionHandler(false);
} else {
//Save user information
completionHandler(true);
}
}];
}
Then, rather than doing something like:
BOOL success = [YourClass getUserInformation];
if (success) {
...
}
You can instead do:
[YourClass getUserInformation:^(BOOL success) {
if (success) {
...
}
}];
// but do not try to use `success` here ... put everything
// contingent upon success inside the above completion handler

Executes dispatch_after when using dispatch_semaphore

I'm having a problem when I want to execute a code inside my dispatch_after block.
First of all, I'm calling a UIActivityIndicator when a button is pressed in order to show it in screen and after the uiactivityindicator starts runnning I want to execute a server call, when I get a response from the server I return that value.
The problem is: When I call my UIAtivityIndicator to run and after that I make my server call, the UIActivityIndicator doesn't show in screen even when the [UIActivityIndicatorInstance startAnimating]; was called and after that the server operation was called.
So I decided to use a dispatch_after in order to wait a certain time after de [UIActivityIndicatorInstance startAnimating]; It works whe I do this, the problem becomes when I have to return the value, so for that reason a use dispatch_semaphore to tell me when the operation has finished and then return the value.
The big problem here is that the dispatch_after is not called.
This is my code, I appreciate you can help me with this problem or some other solution you have in mind.
The main idea that I want to accomplish is that I want to show an UIActivityIndicator while the server operation is executing and when it finishes I want to return that value in the same method.
- (BOOL)getUserSatatus {
// This is when the UIActivityIndicator is starts running
[Tools startActivityIndicator];
double delayInSeconds = 0.5;
// This is used to save server response.
__block BOOL serverResponse;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_time_t executionTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
// I want to execute the server call after a perios of time in order to show first de indicator on screen
dispatch_after(executionTime, dispatch_get_main_queue(), ^{
NSLog(#"This is where the server will call");
// This is when I perform the service call and it returns a values that is
// assigned to server response.
serverResponse = [_backendManager getStatus];
// This is the signal for the semaphore in order to execute the next lines.
dispatch_semaphore_signal(semaphore);
});
// Wait until the signal in order to execute the next line.
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return serverResponse; // Here will be the server return response.
}
You say:
The big problem here is that the dispatch_after is not called.
Yes, that's because you're blocking the main thread with dispatch_semaphore_wait, so the dispatch_after never has a chance to run on the main thread and you're deadlocking.
We can walk you through ways to get around this, but you really shouldn't have synchronous network calls or semaphores in your code at all (for a myriad of reasons, not just for your activity indicator and for solving your deadlocking issue).
You should remove these synchronous network requests, remove the dispatch_after, and remove the semaphores. If you do all of that, and instead follow asynchronous patterns (like using completion blocks), your activity indicator view stuff will then work properly and you won't have any deadlock either.
The correct answer is to refactor the "back end manager" to perform its requests asynchronously (with completion blocks) and then use completion block pattern with getUserStatus method, too.
For example, let's say you fixed getStatus of the _backendManager to behave asynchronously:
- (void)getStatusWithCompletion:(void (^)(BOOL))completion {
NSMutableURLRequest *request = ... // build the request however appropriate
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
BOOL status = ...; // parse the response however appropriate
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(status);
});
}];
[task resume];
}
Then you can refactor the getUserStatus from your question to also take a completion handler:
- (void)getUserStatusWithCompletion:(void (^)(BOOL))completion {
// This is when the UIActivityIndicator is starts running
[Tools startActivityIndicator];
[_backendManager getStatusWithCompletion:^(BOOL status){
[Tools stopActivityIndicator];
if (completion) completion(status);
}
}
And then the code that needs to get the user status would do something like:
[obj getUserStatusWithCompletion:^(BOOL success) {
// use `success` here
}];
// but not here

How to wait for a Parse deleteAllInBackground call to finish?

I am building a simple messaging app using Parse's framework. I have a method called displayMessages. This is called each time the phone receives a push.
However, as this message is doing work in the Parse database I don't want to call it again if it's already running. I want to wait until it is finished and then call it.
I am using the following code:
-(void)receivedPush
{
[self displayMessages];
}
and:
-(void)displayMessages
{
//code here
}
If received push is called I want it to wait until displayMessages is finished before calling it. In displayMessages I have a Parse call:
[PFObject deleteAllInBackground:toDelete block:^(BOOL succeeded, NSError *error) {
}];
It's actually this that I need to wait for, deleteAllInBackground. How can I get around this? I tried using NSOperation queue and that's fine for queuing displayMessages but this won't give my app the desired result because although displayMessages finishes execution at some point it still has deleteAllInBackground running.
If I understand correctly, your requirement is that you only want one "instance" of displayMessages running at one time. What you are asking to do is make displayMessages "threadsafe" What you should do is wrap the code in displayMessages inside #synchronized tags.
What does #synchronized() do?
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
Alternately, you could create some kind of queueing system that uses flags, so recievedPush would actually add the push to a queue and there would be some kind of timer loop that calls display messages repeatedly but only fires when it is done processing.
Edit in response to comment
Create a manual "operation queue" that does what you want it to
- (void) methodThatRunsWhenFiredByTimer {
if (self.flag) {
[self displayMessages];
}
}
- (void) displayMessages {
PushData *data = [self dequeueData]; //maybe, not sure how you're accessing the push data
self.flag = NO;
//Code Here
[PFObject deleteAllInBackground:toDelete block:^(BOOL succeeded, NSError *error) {
//Code Here...
self.flag = YES;
}];
}
- (void) recievedPush:(Pushdata) data {
[self enqueuePushData:data];
}

Testing background save of Core Data entity with Kiwi

I'm struggling to figure out the best method to test interacting with Core Data in a background thread. I have the following class method:
+ (void)fetchSomeJSON
{
// Download some json then parse it in the block
[[AFHTTPClient sharedClient] fetchAllThingsWithCompletion:^(id results, NSError *error) {
if ([results count] > 0) {
NSManagedObjectContext *backgroundContext = //... create a new context for background insertion
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(background, ^{ // If I comment this out, my test runs just fine
//... insert and update some entities
for (NSString *str in results) {
NSManagedObject *object = //...
}
});
}
}];
}
I'm currently testing this method with the following Kiwi code:
describe(#"MyAction", ^{
__block void (^completionBlock)(NSArray *array, NSError *error);
beforeEach(^{
// Stub the http client
id mockClient = [AFHTTPClient mock];
[WRNAPIClient stub:#selector(sharedClient) andReturn:mockClient];
// capture the block argument
KWCaptureSpy *spy = [mockClient captureArgument:#selector(fetchAllThingsWithCompletion:) atIndex:0];
[MyClass fetchSomeJSON]; // Call the method so we can capture the block
completionBlock = spy.argument;
// run the completion block
completionBlock(#[#"blah"], nil);
})
// If I remove the dispatch_async block, this test passes fine.
// If I add it in again the test fails, probably because its not waiting
it(#"should return the right count", ^{
// entityCount is a block that performs a fetch request count
NSInteger count = entityCount(moc, #"Task");
[[theValue(count) should] equal:theValue(4)];
})
// This works fine, but obviously I don't want to wait a second
it(#"should return the right count after waiting for a second", ^{
sleep(1);
NSInteger count = entityCount(moc, #"Task");
[[theValue(count) should] equal:theValue(4)];
});
};
If I remove the dispatch_async line, then I can get my test to run quickly. The only way I can get my test suite to run when using dispatch_async is to sleep(1) after calling the completion block. Using sleep() makes me think that I'm not approaching it in the right way. I have tried using shouldEventually but this doesn't seem to re-fetch my count value.
Have you tried these asynchronous block macros?
#define TestNeedsToWaitForBlock() __block BOOL blockFinished = NO
#define BlockFinished() blockFinished = YES
#define WaitForBlock() while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !blockFinished)
I have tried several approaches to solving this, none feel right.
1) Move the dispatch_async to its own class
+ (void)dispatchOnMainQueue:(Block)block
{
if ([NSThread currentThread] == [NSThread mainThread]) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
+ (void)dispatchOnBackgroundQueue:(Block)block
{
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(background, block);
}
Then during test execution, swizzle the background dispatch to occur on the main queue. This worked, but was unpredictable. It also felt so wrong!
2) Move the setup code to Kiwi's beforeAll block, then sleep the main thread. This works as the Kiwi tests are run on the main thread, so we're effectively saying "let the background operations happen before carrying on with the tests". I think this is what I'm going to use. Yes it makes my unit tests run slower, but they pass when they should do, and fail when they should
describe(#"MyAction", ^{
__block void (^completionBlock)(NSArray *array, NSError *error);
beforeAll(^{
// Stub the http client
id mockClient = [AFHTTPClient mock];
[WRNAPIClient stub:#selector(sharedClient) andReturn:mockClient];
// capture the block argument
KWCaptureSpy *spy = [mockClient captureArgument:#selector(fetchAllThingsWithCompletion:) atIndex:0];
[WRNTaskImporter importAllTasksFromAPI];
completionBlock = spy.argument;
// run the completion block
completionBlock(#[#"blah"], nil);
// Wait for background import to complete
[NSThread sleepForTimeInterval:0.1];
})
// This works
it(#"should return the right count", ^{
// entityCount is a block that performs a fetch request count
NSInteger count = entityCount(moc, #"Task");
[[theValue(count) should] equal:theValue(4)];
})
};
The caveat of this approach is that it only works when you aren't changing any data before a test. Say for example I insert 4 entities, and want to check each entity was inserted as expected. This option would work here. If I needed to re-run the import method and check that the count hadn't increased, I would need to add another [NSThread sleepForTimeInterval:0.1] after calling the insertion code.
For normal block based Kiwi tests you should probably use either the expectFutureValue shouldEventually method, or KWCaptureSpy to test your code, but this may not help when calling nested blocks.
If anyone has a more appropriate method for testing cases like these I'm happy to hear it!

Resources