Singletons and synchronized code

I’ve been making more use of threads and recently needed to allow two threads (neither of them the main thread) to coordinate with each other.    In this particular case I was logging into Parse in one thread and moving some data from the Address Book to Core Data in the other thread.   Once both threads completed, I wanted to call a routine that would allow me to communicate with Parse and update some records in the cloud as needed.

Parse

As an aside, I wanted to put in a quick plug for Parse.  It’s a great service that allows me to persist objects in the cloud, perform queries, etc.   The documentation is great and the team has been very responsive on their forums.  I hope to write about my experience with Parse more extensively in the future.

Singletons

Conceptually, it isn’t difficult to think about how to synchronize the completion of the threads before kicking off my update method.   I just need to keep a flag somewhere that both threads can check.

@property (nonatomic) BOOL readyForParseUpdate;

Once either thread completes, it checks the flag.  If set it calls the update method, otherwise it sets the flag and does nothing (this works since I am only coordinating 2 threads).

The first problem is getting access to this shared resource.  This is where a Singleton can help.  Apple talks about singletons in the document section Creating a Singleton Instance and gives the definition of one as “… the sole allowable instance of a class in the current process”.   Using a singleton allows us to share a resource similar to how we might use a global variable.

Matt Gallagher wrote a great article that discussed this titled “Singletons, AppDelegates and top-level data“.   In the article he provides a link to a header file he wrote called CWLSynthesizeSingleton.h that contains macros used to create the necessary singleton methods.   I found this header to be invaluable for creating singletons when needed.

Implementing our readyForParseUpdate flag in a singleton

I created an Objective-C class called CommonStateSingleton and used Matt Gallagher’s header file.

CommonStateSingleton.h

#import "CWLSynthesizeSingleton.h"

@interface CommonStateSingleton : NSObject

CWL_DECLARE_SINGLETON_FOR_CLASS(CommonStateSingleton)

@property (nonatomic) BOOL readyForParseUpdate;

@end

CommonStateSingleton.m

#import "CommonStateSingleton.h"

@interface CommonStateSingleton ()
@end

@implementation CommonStateSingleton

CWL_SYNTHESIZE_SINGLETON_FOR_CLASS(CommonStateSingleton);

@synthesize readyForParseUpdate = _readyForParseUpdate;

// Not ready for Parse Compare Phases by default.
- (BOOL)readyForParseUpdate {
    if(!_readyForParseUpdate){
        _readyForParseUpdate = NO;
    }

    return _readyForParseUpdate;
}

@end

Here’s an example of how we can set the flag from our main code:

// The name "sharedCommonStateSingleton" is special here.  It is the prefix "shared" in front of our class name.
[[CommonStateSingleton sharedCommonStateSingleton] setReadyForParseUpdate:YES];

Synchronizing the thread completions

The singleton methods contain locking code to allow multiple threads to access properties safely, but we still need to guard against race conditions when kicking off our update method.  Suppose both threads complete at the same time.  They both check the readyForParseUpdate flag and find it set to NO.  They both then set it to YES and then do nothing.  Our update method is never called.

What we want to do is to check our flag,  set it if NO, and call our update method if  it was already YES – all as an atomic transaction.

Objective-C provides several means of synchronizing code as mentioned in the post How to Implement Semaphores in iOS Application?    I chose to use @synchronized which is documented in the section Using the @synchronized Directive.

To accomplish the synchronization I introduced an NSString property in CommonStateSingleton called parseLoginLockObj as well as a new BOOL flag called parseUserLoggedIn.  Upon completion each thread calls into the main thread to execute the synchronization code. Here’s what I ended up with:

Core Data thread completion:


// Created a string in CommonStateSingleton to lock on for @synchronized
id parseLoginLockObj = [[CommonStateSingleton sharedCommonStateSingleton] parseLoginLockObj];

@synchronized(parseLoginLockObj){

    // User has already logged in. Call update method
    if([[CommonStateSingleton sharedCommonStateSingleton] parseUserLoggedIn]){
            // Call update method
    }

    // User not logged in yet.  Signal that we are ready for Parse update upon login.
    else {
        [[CommonStateSingleton sharedCommonStateSingleton] setReadyForParseUpdate:YES];
    }

}

Parse login thread completion:

id parseLoginLockObj = [[CommonStateSingleton sharedCommonStateSingleton] parseLoginLockObj];

@synchronized(parseLoginLockObj){

    // Mark user as logged in
    [[CommonStateSingleton sharedCommonStateSingleton] setParseUserLoggedIn:YES];

    // If we are late logging in and Core Data thread is complete, call Parse update method.
    if([[CommonStateSingleton sharedCommonStateSingleton] readyForParseUpdate]){
        // Call update method
    }

}

The blocks starting with @synchronized(parseLoginLockObj) { … } are guaranteed not to execute concurrently.     If one block is executing, the other will wait until the first is done.

I didn’t technically need the additional flag parseUserLoggedIn, but wanted to use  parseUserLoggedIn elsewhere in my code so I introduced it here.

Advertisements

4 responses to “Singletons and synchronized code

  1. Pingback: Flexible method calls with NSInvocation | Finalize.com: My journey with iOS and other code adventures

  2. Pingback: Unit Testing View Controllers and Asynchronous APIs | Finalize.com: My journey with iOS and other code adventures

  3. Pingback: Functional Coverage and Coverpoints | Finalize.com: My journey with iOS and other code adventures

  4. Pingback: The development of Contacts2Web | Finalize.com: My journey with iOS and other code adventures

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s