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?