Simplified NSUserDefaults

I use NSUserDefaults all the time for storing simple users settings and application state.  But there’s a whole lotta string literals and a bunch of repeating yourself that takes place.  That sucks ….

So I like to create a category on NSUserDefaults so I can treat it like a concrete class, whose API is enforced by the compiler and autocompleted by Xcode.  Here’s an example of how I use it to track a users email address within my app.  Note the rcast_ prefix.  Always a good idea to prefix your categories to prevent future name collisions.

//NSUserDefaults_RCastr.h
@interface NSUserDefaults (RCastr)

@property (assign, getter=rcast_userEmail,
           setter=rcast_setUserEmail:) NSString *rcast_userEmail;

//NSUserDefaults_RCastr.m
#import "NSUserDefaults+RCastr.h"
NSString *const rcastDefaultsKeyUserEmail = @"rcast_userEmail";

@implementation NSUserDefaults (RCastr)

#pragma mark -
#pragma mark Username

- (NSString *)rcast_userEmail {
    return [self stringForKey:rcastDefaultsKeyUserEmail];
}

- (void)rcast_setUserEmail:(NSString *)userEmail {
    [self setObject:userEmail forKey:rcastDefaultsKeyUserEmail];
    [self synchronize];
}

@end

That allows me to use user defaults like the following:


    //Set the email address
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    defaults.rcast_userEmail = @"user@domain.com";

    //Get the email address
       NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if (defaults.rcast_userEmail){
        [FlurryAnalytics setUserID:defaults.rcast_userEmail];
    }

Dead easy change, but much cleaner and far less error prone.

Linkedin oAuth desktop c# sample embedded webBrowser

I’ve created and uploaded some sample code for using Linkedin’s oauth library in a c# desktop app.  Faith Yasar’s c# code was my starting point.  A bit of a refactor of the oAuth librarie to include the oauth_callback parameter was needed, as well as code for displaying the login dialog.

Code can be found here in a forum post I made on linkedin.

The code contained includes a test harness as well as the oauth libraries for oauth login dance and Linkein API requests.  Oauth login is handled with an embedded webBrowser which is shown modally for the user to login.  Upon login completion, dialog will be closed and the token and verifier will be available from the dialogs property.

To use the code, simply Add your Linkedin consumer secret and Consumer key to the OauthLinkedIn.cs file:

private string _consumerKey = "ENTER_YOUR_CONSUMER_KEY";
private string _consumerSecret = "ENTER_YOUR_CONSUMER_SCRET";

Then you can make api calls following a few steps:

OAuthLinkedIn _oauth = new OAuthLinkedIn();
String requestToken = _oauth.getRequestToken();
_oauth.authorizeToken();
String accessToken = _oauth.getAccessToken();</div>

Hope that helps

oAuth authorization callback on the iPhone with WebView

There was a bit of chatter a while back about handling oAuth on the iPhone; in particular security balances sending a user to the website using Safari vs an embedded WebView.  Mike’s blog post discusses this so I won’t repeat, other than to say that I think either solution (webView or Safari) is open for spoofing.  An app developer could spoof an auth and grab creds in either case pretty easily … so I’ve chosen to optimize for user experience by implemented an oAuth webView for our app.

Here’s some of the relevant code for launching to an authorize website and handling the response.

* Our app uses oAuthConsumer library

* Our implimentation was against linkedin oauth which meant that I needed to pass the oauth_callback in our request token request by setting the oauth_callback parameter there rather than the authorize URL

In other words, our requestToken method looks something like the following:


OAMutableURLRequest                *request = [[[OAMutableURLRequest alloc] initWithURL: self.requestTokenURL consumer: self.consumer token:nil realm:nil signatureProvider: nil] autorelease];
 if (!request) return;
 [request setHTTPMethod: @"POST"];
 [request setParameters: [NSArray arrayWithObject: [[[OARequestParameter alloc] initWithName: @"oauth_callback" value: kLinkedInCallbackUrl] autorelease]]];
 OADataFetcher                *fetcher = [[[OADataFetcher alloc] init] autorelease];
 [fetcher fetchDataWithRequest: request delegate: self didFinishSelector: @selector(setRequestToken:withData:) didFailSelector: @selector(outhTicketFailed:data:)];

With the request token set, we’re able to pass this to the authorize url and it will return to our custom url

/*Create the request object for the linkedin URL*/


if (!_requestToken.key && _requestToken.secret) return nil;    // we need a valid request token to generate the URL

 OAMutableURLRequest            *request = [[[OAMutableURLRequest alloc] initWithURL: self.authorizeURL consumer: nil token: _requestToken realm: nil signatureProvider: nil] autorelease];

 [request setParameters: [NSArray arrayWithObject: [[[OARequestParameter alloc] initWithName: @"oauth_token" value: _requestToken.key] autorelease]]];

/*Load the webview with this request*/


[_webView loadRequest: request];

/*Check the response for a custom uri and redirect if it's set*/
- (BOOL) webView: (UIWebView *) webView shouldStartLoadWithRequest: (NSURLRequest *) request navigationType: (UIWebViewNavigationType) navigationType {
 NSData                *data = [request HTTPBody];
 char                *raw = data ? (char *) [data bytes] : "";
 NSURL* url = request.URL;

 if ([url.scheme isEqualToString:@"liconnect"]) {
 [_spinner stopAnimating];
 if ([url.resourceSpecifier isEqualToString:@"cancel"]) {
 if ([_delegate respondsToSelector:@selector(OAuthLinkedInAuthorizeViewFailed:)]) {
 [_delegate OAuthLinkedInAuthorizeViewFailed:self];
 }
 }
 else {
 [self dialogDidSucceed:url];
 }

 return NO;
 }

 if (raw && strstr(raw, "cancel=Deny")) {
 [self denied];
 return NO;
 }
 if (navigationType != UIWebViewNavigationTypeOther) _webView.alpha = 0.1;
 return YES;
}

/*Strip out the token and auth_verifier from the url*/


- (void)dialogDidSucceed:(NSURL*)url {
 NSString* q = url.query;
 NSLog(q);
 NSRange verifier_start = [q rangeOfString:@"oauth_verifier="];

 NSRange start = [q rangeOfString:@"auth_token="];
 if (start.location != NSNotFound) {
 NSRange end = [q rangeOfString:@"&"];
 NSUInteger offset = start.location+start.length;
 NSString* token = end.location == NSNotFound
 ? [q substringFromIndex:offset]
 : [q substringWithRange:NSMakeRange(offset, end.location-offset)];

 NSString* verifier = [q substringFromIndex:verifier_start.location+verifier_start.length];
 if (token&&verifier) {
 if ([_delegate respondsToSelector:@selector(requestTokenReceived:withVerifier:)]){
 [_delegate requestTokenReceived:token withVerifier:verifier];
 }
 }
 else
 {
 if ([_delegate respondsToSelector:@selector(OAuthLinkedInAuthorizeViewFailed:)]){
 [_delegate OAuthLinkedInAuthorizeViewFailed:self];
 }        }
 [self removeFromSuperview];
 }
}

You’re done.  You’ve now got your oauth_verifier and your access token all lined up to store away or make immediate calls to the api.

Computer Science Is Dead

I just finished reading Short history of Progress. A great read, and falls nicely into this pseudo hippie/midlife crisis I find myself in.

My extremely limited literary genius tells me that one of the core themes of the book is that throughout the history of man, science has advanced, in occasions too fast for the good of society. Ronald Wright does a nice job of showing this through examples of “progress traps” ie. Babylon fell as a result of their very own success through sophisticated wet agriculture practices leading to increased food yeilds, cities and wealth, but also, eventually salination and death of the soil.

I’ll take a gigantic leap and compare the death of a culture … with advances in programming tools leading to the death of computer scientists, as I recently heard a peer boast.

Ok, that’s a bit extreme … a lot extreme actually … and even more naive. While the likes of auto-generated code, garbage collectors, intellisense, .net and rails frameworks have in many ways, allowed pragmatic and scientific skills to be optional when writing code; much like any other science, advances in the tools allows the scientist to focus on other areas of their domain.

Stating that computer science was dead because of an advanced compiler would be like claiming mechanical engineering was toast because of the invention of the wheel. To me, computer science ultimately comes down to mathematical logic, category theory, domain theory, and algebra. Having an IDE doesn’t help me out in any of these areas.