2

I use the following method to attempt to synchronously obtain an OAuth access token within 10 seconds, otherwise return nil. It works fine, however as an exercise I would like to convert my code to use a semaphore.

The Runloop version

- (NSString*)oAuthAccessToken
{
    @synchronized (self)
    {
        NSString* token = nil;
        _authenticationError = nil;
        if (_authentication.accessToken)
        {
            token = [NSString stringWithFormat:@"Bearer %@", _authentication.accessToken];
        }
        else
        {
            [GTMOAuth2ViewControllerTouch authorizeFromKeychainForName:_keychainName authentication:_authentication];
            [_authentication authorizeRequest:nil delegate:self didFinishSelector:@selector(authentication:request:finishedWithError:)];
            for (int i = 0; i < 5; i++)
            {
                [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
                if (_authentication.accessToken)
                {
                    token = [NSString stringWithFormat:@"Bearer %@", _authentication.accessToken];
                    break;
                }
                else if (_authenticationError)
                {
                    break;
                }
            }
        }
//        LogDebug(@"Returning token: %@", token);
        return token;
    }
}

Semaphore Version

The semaphore version of the code goes a little something like this:

- (NSString*)oAuthAccessToken
{
    @synchronized (self)
    {
        NSString* token = nil;
        _authenticationError = nil;
        if (_authentication.accessToken)
        {
            token = [NSString stringWithFormat:@"Bearer %@", _authentication.accessToken];
        }
        else
        {
            _authorizationSemaphore = dispatch_semaphore_create(0);
            dispatch_async(_authorizationRequestQueue, ^(void)
            {
                [GTMOAuth2ViewControllerTouch authorizeFromKeychainForName:_keychainName authentication:_authentication];
                [_authentication authorizeRequest:nil delegate:self didFinishSelector:@selector(authentication:request:finishedWithError:)];
            });
            dispatch_semaphore_wait(_authorizationSemaphore, DISPATCH_TIME_FOREVER);
            if (_authentication.accessToken)
            {
                token = [NSString stringWithFormat:@"Bearer %@", _authentication.accessToken];
            }
        }
        return token;
    }
}

Gotcha!!! GTMOAuth2 sometimes returns immediately

  • When GTMOAuth2 needs to hit the network it calls back via a delegate method. In this method I signal my semaphore.
  • Sometimes GTMOAuth2 is able to return immediately. The problem is the method returns void.

How can I signal my semaphore in the latter case? If I add an observer to the authentication.assessToken will it be fired?

Jasper Blues
  • 28,258
  • 22
  • 102
  • 185

1 Answers1

3

I'm not familiar with the GTMOAuth2 library but authentication.accessToken is a property, so and there doesn't seem to be anything that prevents it from being KVO compliant. Adding an observer should work for you in all cases, both for the async and the sync. Therefore, I'd consider only the async case.

If you want to make your solution even cleaner, then you should definitely try Reactive Cocoa.

allprog
  • 16,540
  • 9
  • 56
  • 97
  • 1
    Yes, turns out it does work just fine. I think I was most of the way to solving my issue by the time I posted, but this info might be useful for others, so leaving it all up here. . I learned two things myself to: a) Observer should work for both sync and async b) Check out Reactive Cocoa – Jasper Blues Sep 26 '13 at 09:51
  • 1
    @JasperBlues I'll definitely have to try Typhoon. I was looking at it a while ago but now as it has become ready for deployment I'm totally eager to try it out. – allprog Sep 26 '13 at 10:00
  • Your feedback will be really valuable to us :) – Jasper Blues Sep 26 '13 at 10:15
  • 2
    Have grocked Reactive Cocoa and love it. I can't believe I haven't tried it until now. Thanks :) – Jasper Blues Sep 26 '13 at 12:56
  • If you like the AppCode IDE, I've raised a ticket for tighter RAC support: http://youtrack.jetbrains.com/issue/OC-8342 . . they are usually very fast at reacting to feedback. (Like RAC, hehe) . . please vote if you're interested in issue. – Jasper Blues Sep 26 '13 at 22:50