A Single Sign-on Pattern for Enterprise iOS Applications

In conversations with clients, we continue to hear how important single sign-on is to their enterprise mobile application strategy. According to a study earlier this year by Kelton Research 250 IT Managers, 21% of respondents indicated that they plan to deploy 20, or more, enterprise applications to their organization this year.

In order for enterprises to realize the productivity gains factored into the investment decisions for those applications, IT Managers must explore options for enabling single sign-on for their users. In this post, we’ll outline a mobile single sign-on (mSSO) pattern for enterprise iOS applications.


  1. Your company has a centralized single sign-on service exposed on the network – LDAP, Novell Access Manager, etc. This approach will work with a number of identity management architectures, but you will need to tailor credential management accordingly. For this demo, our service calls are simulated with hardcoded tokens.
  2. Your company has a standardized credential timeout period or a way of dynamically distributing that value to applications. For this demo, we’ll use a static 30 minute timeout period.
  3. You are able to sign and distribute builds to a device. This is important because keychain activities do not function in the simulator.



Our approach will consist of creating three applications – two mock business applications and one logout application. Each application may contain its own logout functionality, but a single logout application makes the user’s activity of killing a session intuitive. In practice, the mSSO pattern would be implemented as a stand-alone library which could be easily dropped into each of your various enterprise applications.

The business applications retrieve a unique authentication token which is included with each service request. This token will be stored in the device’s keychain, which will be shared across our suite of applications. We will also maintain an ‘expiration date’ within the keychain so that subsequent requests from our various apps can (if required) preemptively prompt the user to authenticate.

Authentication for this demo may be simplistic, but existing patterns cover implementing authentication in a service-based mobile application. For example, the ‘store credentials’ logic presented in this example would live somewhere in that pattern’s “authenticateOperation”.

One possible extension of the mSSO pattern is to confirm that your credentials have not expired before issuing a call to the service. You would use the mSSO pattern to sign your network requests, but rely on the service and response handlers to inform you that credentials have expired. Checking credential expiration prior to making a service call limits unnecessary network traffic.


There are two key steps that must be completed in order for your applications to share keychain access.

  1. Each application included in your mSSO effort must share a Bundle Seed ID, which allows shared keychain access between our suite of applications. This is configured within the iOS management portal. We’ll configure our applications using the default ‘Team ID’ selection.

  2. We also need to enable and add an entitlements file that specifies that this application should be able to access the shared keychain. This step is done after the Xcode project has been created.
    • Select your app target in Xcode and choose the ‘Summary’ tab.
    • Choose ‘Enable Entitlements’ at the bottom.
    • Set the Entitlements File name to “mSSO” and hit return. Select ‘Create’ when prompted.
    • Unless needed for your application, remove iCloud configuration settings.
    • Add a keychain value titled “mSSO”, our Bundle Seed ID is prepended to this value for us.


We’ll walk through how to create App1 in detail, and then let you work through App2 and the Logout application. Let’s start by opening Xcode and creating a single view application. Before we get started, add the Security.framework and create your entitlement files as outlined above. Here is a good primer for interacting with the keychain.

  1. Add the custom mSSOUtils and DateUtils classes as outlined below. Make sure that you import accordingly. Due to changes in iOS related to ARC (developer account required), you will need to disable ARC for the mSSOUtils class. You can do so by selecting your target in Xcode and viewing the Build Phases tab. Expand the Compile Sources section and double click the mSSOUtils class to add the -fno-objc-arc compiler flag. You may need to clean and build.

    #define kmSSOKeychainGroup @"3Q4M6DQ9WM.mSSO"
    #define kAuthenticationServiceName @"com.captechconsulting.msso"
    #define kCredentialToken @"mSSOAuthenticationToken"
    #define kCredentialExpiration @"mSSOCredentialsExpirationDate"
    #define kExpirationTimeout 60.0 * 30    // 30 minute timeout
    // *** PRIVATE METHODS DEF *** //
    @interface mSSOUtils (Private)
    + (NSMutableDictionary *) keychainSearch:(NSString *)identifier;
    + (NSString *) getValueForIdentifier:(NSString *)identifer;
    + (BOOL) setValue:(NSString *)value forIdentifier:(NSString *)identifier;
    + (void) deleteValueForIdentifier:(NSString *)identifier;
    @implementation mSSOUtils:
    + (BOOL) authenticateWithUsername:(NSString *)username andPassword:(NSString *)password {
        // for testing purposes, each call to this method authenticates successfully
        // set the token - app specific - change this in your App2 implementation
        if ([self setValue:@"TokenSetFromApp1" forIdentifier:kCredentialToken]) {
            // token set, now set the credential expiration
            [self extendCredentials];
        } else {
            NSLog(@"Unable to set token.");
        return YES;
    + (void) logout {
        // destroy token AND expiration date
        [self deleteValueForIdentifier:kCredentialToken];
        [self deleteValueForIdentifier:kCredentialExpiration];
    // credential management
    + (void) extendCredentials {
        NSDate *newExpireDate = [DateUtils dateWithTimeout:kExpirationTimeout];
        NSString *newExpireString = [DateUtils stringFromDate:newExpireDate withFormat:kDateFormat];
        BOOL success = [self setValue:newExpireString forIdentifier:kCredentialExpiration];
        if (!success) {
            NSLog(@"Unable to extend credentials.");
    + (BOOL) credentialsExpired {
        // if no token exists, call credentials expired
        if ([self credentialToken] == nil) {
            return YES;
        NSDate *expirationDate = [self credentialExpirationDate];
        if (expirationDate) {
            // check for expiration
            return [DateUtils dateInPast:expirationDate];
        // if there is no expiration date, default to 'expired'
        return YES;
    // sign the request with current credentials - we'll add the token as an HTTP header field
    + (NSMutableURLRequest *) signRequest:(NSMutableURLRequest *)request {
        NSString *token = [self credentialToken];
        if (token) {
            [request addValue:token forHTTPHeaderField:@"auth-token"];
        return request;
    // methods to retrieve credential information
    + (NSString *) credentialToken {
        NSString *token = [self getValueForIdentifier:kCredentialToken];
        return token;
    + (NSDate *) credentialExpirationDate {
        NSString *expirationDateString = [self getValueForIdentifier:kCredentialExpiration];
        if (expirationDateString) {
            // convert to date
            return [DateUtils dateFromString:expirationDateString withFormat:kDateFormat];
        return nil;
    + (void) displayAuthenticateView:(UIViewController *)vc {
        authenticateViewController *authenticateView = [[authenticateViewController alloc] initWithNibName:@"authenticateViewController" bundle:nil];
        UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:authenticateView];
        [vc presentModalViewController:nc animated:YES];
    #pragma mark -
    #pragma mark PRIVATE METHODS
    + (NSMutableDictionary *) keychainSearch:(NSString *)identifier {
        NSMutableDictionary *keychainSearch = [[[NSMutableDictionary alloc] init] autorelease];
        [keychainSearch setObject:kmSSOKeychainGroup forKey:(id)kSecAttrAccessGroup];   // inform the search that we're using the shared keychain
        [keychainSearch setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];   // set the type to generic password - other options are certification, internet password, etc
        NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
        [keychainSearch setObject:encodedIdentifier forKey:(id)kSecAttrGeneric];
        [keychainSearch setObject:encodedIdentifier forKey:(id)kSecAttrAccount];
        [keychainSearch setObject:kAuthenticationServiceName forKey:(id)kSecAttrService];
        return keychainSearch;
    + (NSString *) getValueForIdentifier:(NSString *)identifier {
        NSMutableDictionary *search = [self keychainSearch:identifier];
        [search setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; // limit it to the first result
        [search setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];    // return data vs a dictionary of attributes
        NSData *value = nil;
        OSStatus status = SecItemCopyMatching((CFDictionaryRef)search,
                                              (CFTypeRef *)&value);
        if (status == noErr) {
            return [NSString stringWithUTF8String:[value bytes]];;
        return nil;
    + (BOOL) setValue:(NSString *)value forIdentifier:(NSString *)identifier {
        // check if value exists
        NSString *existingValue = [self getValueForIdentifier:identifier];
        if (existingValue) {
            if (![existingValue isEqualToString:value]) {
                // update value
                NSMutableDictionary *search = [self keychainSearch:identifier];
                NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
                NSMutableDictionary *update = [NSMutableDictionary dictionaryWithObjectsAndKeys:valueData, (id)kSecValueData, nil];
                OSStatus status = SecItemUpdate((CFDictionaryRef)search,
                if (status == errSecSuccess) {
                    return YES;
                return NO;
        } else {
            // create new entry
            NSMutableDictionary *add = [self keychainSearch:identifier];
            NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
            [add setObject:valueData forKey:(id)kSecValueData];
            OSStatus status = SecItemAdd((CFDictionaryRef)add,NULL);
            if (status == errSecSuccess) {
                return YES;
            return NO;
        return YES;
    + (void) deleteValueForIdentifier:(NSString *)identifier {
        NSMutableDictionary *search = [self keychainSearch:identifier];


    + (NSDate *) dateFromString:(NSString *)string withFormat:(NSString *)format {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    	[dateFormatter setDateFormat:format];
    	NSDate *date = [dateFormatter dateFromString:string];
    	return date;
    + (NSString *) stringFromDate:(NSDate *)date withFormat:(NSString *)format; {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    	[dateFormatter setDateFormat:format];
    	NSString *dateString = [dateFormatter stringFromDate:date];
        return dateString;
    + (NSDate *) dateWithTimeout:(NSTimeInterval)timeout {
        NSDate *now = [NSDate date];
        NSDate *timeoutDate = [now dateByAddingTimeInterval:timeout];
        return timeoutDate;
    + (BOOL) dateInPast:(NSDate *)date {
        if ([date compare:[NSDate date]] == NSOrderedAscending) {
            return YES;
        return NO;
  2. Within the generated ViewController, add two UILabel outlets/properties – token and expiration date – and a “Logout” button. You’ll need to add two custom methods: logout and a selector to handle the foreground notification we register to receive.
    - (IBAction) logout:(id)sender {
        [mSSOUtils logout];
        [mSSOUtils displayAuthenticateView:self];
    - (void) enterForeground:(id)sender {
        // reset labels as we've entered the foreground
        self.token.text = [mSSOUtils credentialToken];
        self.expiration.text = [DateUtils stringFromDate:[mSSOUtils credentialExpirationDate] withFormat:kDateFormat];
  3. You should only need to update two view lifecycle methods within ViewControllerviewDidLoad and viewWillAppear. Within viewDidLoad, we register to receive a notification when the app is brought to the foreground that triggers our UI updates. The additions to viewWillAppear simply update our labels if there is data in the keychain.
    - (void)viewDidLoad {
        [super viewDidLoad];
        // register for enter foreground notification to update labels
        [[NSNotificationCenter defaultCenter] addObserver:self 
    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        self.token.text = [mSSOUtils credentialToken];
        self.expiration.text = [DateUtils stringFromDate:[mSSOUtils credentialExpirationDate] withFormat:kDateFormat];
  4. Add an authenticateViewController to your project. This will be displayed modally when the users credentials need to be re-challenged. This example simply has a login button, but this is where you would include typical login fields.
    - (IBAction) authenticate:(id)sender {
        // if authentication is successful, dismiss the view
        if ([mSSOUtils authenticateWithUsername:@"username" andPassword:@"hashedPassword"]) {
            [self dismissModalViewControllerAnimated:YES];
  5. Last up, we’ll need to update our application delegate to confirm our credentials are valid when the app launches or is brought back from the background. You’ll need to update the didFinishLaunchingWithOptions and applicationWillEnterForeground methods as noted below:
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        self.window.rootViewController = self.viewController;
        [self.window makeKeyAndVisible];
        // credentials don't exist or are expired - display the authenticate view
        if ([mSSOUtils credentialsExpired]) {
            [mSSOUtils displayAuthenticateView:self.viewController];
        return YES;
    - (void)applicationWillEnterForeground:(UIApplication *)application {
        // credentials don't exist or are expired - display the authenticate view
        if ([mSSOUtils credentialsExpired]) {
            [mSSOUtils displayAuthenticateView:self.viewController];
  6. Now, rinse and repeat for App2. You can follow the same steps for the Logout application, but you really just need a single view that calls [mSSOUtils logout] on launch and informs the user their credentials have been terminated.
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        self.window.rootViewController = self.viewController;
        [self.window makeKeyAndVisible];
        // logout to kill credentials
        [mSSOUtils logout];
        return YES;
    - (void)applicationWillEnterForeground:(UIApplication *)application {   
        // logout to kill credentials
        [mSSOUtils logout];

Here are a couple helpful hints while developing your solution:

  • We’ve disabled ARC for the mSSOUtils class, which means you need to handle memory management yourself.
  • When building your application, if you get a Mach-O Linker error, ensure that you’ve added the Security.framework.


Our testing won’t get too crazy, but at this point you should be all set to install our suite of apps on your device.

We’ll start by opening App1 and simulating an authentication call. Once the modal view is dismissed, our token and expiration date should be updated – expiration being now + 30 minutes. From here, jump to App2 where you should see the App1 token/expiration. Logout and re-authenticate within App2, which will update our token and expiration date. Now, we’ll wait 30 minutes and test whether our token expires. After 30 minutes, open App1, you should be prompted with an authentication view. Authenticate and then open the Logout app. Enter App2 from the multi-task tray, you should be prompted to authenticate once again.

The test sequence above has been captured in the screenshots below. Note: for brevity, I’ve excluded screenshots of each authentication view except for the final step.


This post presents a pattern for implementing single sign-on for your enterprise iOS applications. It should give you the foundation needed to begin implementing single sign-on in your applications. I’ve attached the source for App1. If you’ve got questions or are interested in additional source files, I’m @nathanhjones on Twitter.

Project files:
Did you like this? Share it:



Getting Started with JSON in iOS5

Update: This post has been cross-posted on my employers blog.

JSON has taken the data-interchange world by storm with its’ lightweight, easy to understand format. The explosion of mobile apps, and their consumption of network based data, helped fuel JSON’s growth. CapTech’s (my employer) recommended approach for web services utilizes JSON as the interchange format.

While JSON has been around for several years – RFC4627 was published in July of 2006 – working with JSON in an iOS project required that you download one of the many frameworks and integrate it into your project. My personal choice has been SBJSON –

However, with the release of iOS5, Apple has finally included native support for reading and writing JSON with the class NSJSONSerialization.

Why might you consider using the native JSON API? First and foremost, Apple delivered, Apple supported. While support for most third-party libraries is good, you can’t beat updated, built-in, backwards compatible support (for future versions of the OS) on day one of a new SDK.

One unfortunate con, use of NSJSONSerialization is limited to devices running iOS5. While iOS5 adoption is moving at a great pace, this still vastly limits your install base. In the case of some enterprises with field devices deployed with previous versions of the OS, this may not be an option for quite some time.

It’s important to note, calling any of the NSJSONSerialization methods on a device running an older version of iOS will not cause the application to crash. It simply won’t work and will continue on as if the call was never made. Obviously, there are other impacts of this, but this may fit some needs.

Now, let’s cover implementing the 4 read/write methods that Apple has exposed. As you can see below, using NSJSONSerialization in your projects is incredibly easy, typically requiring just a few lines of code. NSJSONSerialization supports the reading and writing of JSON data via static data or an instance of NS*Stream. The NS*Stream examples below are rudimentary, but they convey what is needed in order for NSJSONSerialization to do its’ job.

Parsing JSON Data

The parsing methods accept an options parameter which allow you to pass different instructions to manipulate what type of foundation object you get back.

  • NSJSONReadingAllowFragments: instructs the parser to allow top-level objects that are neither an NSArray nor NSDictionary
  • NSJSONReadingMutableContainers: instructs the parser to generate NSMutableArray and NSMutableDictionary objects
  • NSJSONReadingMutableLeaves: instructs the parser to generate NSMutableString objects

Method: JSONObjectWithData

This method allows us to create a JSON object from an instance of NSData.  In this example, we’ll assume that an authentication request was successful (see below).  The first portion of the code will be to generate the mock-JSON response we received from the service.  The code will parse that response and create a foundation object.  From there, we’ll check if the object is an NSDictionary (there are a couple ways of doing this) and, if so, log the returned message and my token.

    NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:@"Authentication Successful", @"auth_response",@"abc123", @"auth_token", nil];
    NSError *writeError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:&writeError];
    // parse the JSON data into what is ultimately an NSDictionary
    NSError *parseError = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&parseError];
    // test that the object we parsed is a dictionary - perhaps you would test for something different
    if ([jsonObject respondsToSelector:@selector(objectForKey:)]) {
        NSLog(@"Response: %@", [jsonObject objectForKey:@"auth_response"]);
        NSLog(@"Token: %@", [jsonObject objectForKey:@"auth_token"]);

Method: JSONObjectWithStream

This method allows us to create a JSON object from an input stream. When and why to use NSInputStream is out of scope for this post. However, if you have a large chunk of JSON data you want to parse, it may be one option to explore.

In this example, we create an instance of NSData that contains JSON formatted tweet information. While not the recommended network communication approach, this allows us to quickly generate an NSData object for our stream.  Once the stream is up, we’ll create a foundation object from the JSON data, test that it is an NSDictionary (which we expect given the source data we’re retrieving), and then log the tweet to the console.

It’s important to note that an NS*Stream must be created AND configured in order for NSJSONSerialization to work properly. Once parsed, we simply log each of the tweets to the console.

    NSData *tweets = [NSData dataWithContentsOfURL:[NSURL URLWithString:@""]];
    NSInputStream *twitterStream = [[NSInputStream alloc] initWithData:tweets];
    [twitterStream open];
    if (twitterStream) {
        NSError *parseError = nil;
        id jsonObject = [NSJSONSerialization JSONObjectWithStream:twitterStream options:NSJSONReadingAllowFragments error:&parseError];        
        if ([jsonObject respondsToSelector:@selector(objectForKey:)]) {
            for (NSDictionary *tweet in [jsonObject objectForKey:@"results"]) {
                NSLog(@"Tweet: %@", [tweet objectForKey:@"text"]);
    } else {
        NSLog(@"Failed to open stream.");

Writing JSON Data

The JSON writing methods also have an options parameter, but it’s currently limited to a single option.

  • NSJSONWritingPrettyPrinted: instructs the writer to generate JSON with whitespace designed to make output more readable. If this option is not used, the most compact JSON possible will be generated.

Method: dataWithJSONObject

This method allows us to create a JSON formatted NSData object from a foundation object – typically NSDictionary or NSArray.

In this example, we’ll build a dictionary of authentication credentials and then convert that to JSON as if we were posting it to an authentication service.

    NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:@"", @"user",@"mypass", @"pass", nil];
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:&writeError];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSLog(@"JSON Output: %@", jsonString);

Method: writeJSONObject:toStream

This method allows us to write our JSON directly to an output steam. Again, when to use NSOutputStream is out of scope for this post, but it is an option. For this example, we’ll build an array of all tweet details for my last 3 tweets. We’ll then scrub that data down to 3 key pieces of information for each tweet, which we will then write to an output stream. In this case, we’ll simply write the contents to a local file.

// get tweet data and convert to foundation object
    NSData *tweetData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@""]];
    NSError *parseError = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData:tweetData options:NSJSONReadingAllowFragments error:&parseError];
    // initialize an array to hold our reformatted tweets
    NSMutableArray *tweets = [[NSMutableArray alloc] init];
    // check that we received a dictionary - there are 'header' objects sent by twitter
    if ([jsonObject respondsToSelector:@selector(objectForKey:)]) {
        // loop through all the actual tweets
        for (NSDictionary *tweet in [jsonObject objectForKey:@"results"]) {   
            // create a dictionary of minimal tweet data and add to output
            NSDictionary *scrubbedTweet = [NSDictionary dictionaryWithObjectsAndKeys:
                                           [tweet objectForKey:@"id"], @"id",
                                           [tweet objectForKey:@"created_at"], @"created_at",
                                           [tweet objectForKey:@"text"], @"text",
            [tweets addObject:scrubbedTweet];        
    // initialize and open the stream
    NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *path = [NSString stringWithFormat:@"%@/tweets.json", documents];
    NSOutputStream *stream = [[NSOutputStream alloc] initToFileAtPath:path append:YES];
    [stream open];
    // write JSON representation of our tweet array to file
    NSError *writeError = nil;
    NSInteger bytesWritten = [NSJSONSerialization writeJSONObject:tweets toStream:stream options:NSJSONWritingPrettyPrinted error:&writeError];
    if (bytesWritten <= 0) {
        NSLog(@"Error writing JSON Data");

One additional method I find particularly interesting, isValidJSONObject.  An easy way to validate that the object you’ve created can be converted to JSON data.  I could be wrong, but I don’t recall any of the third-party libraries I’ve used having such a method.

If you’ve got questions, I’m @nathanhjones.

Did you like this? Share it:



Creating Reusable UIViews with a Drop Shadow [Tutorial]

Update: I’ve updated the post to reflect what code requires iOS 4.0 and later.  Basically, the layer properties for the drop shadow.

I’m working on an internal iPhone application for my employer.  It’s data-centric, as I’m sure most enterprise grade apps are, and as such consists mostly of UITableViews so users can view and drill into each subsequent level of detail.

One requirement was to have summary data points from previous screens on each view.  Nothing mind blowing that a tableHeaderView couldn’t solve.  However, a couple of these summary views would be reused and had several data points.  To complicate things, I needed a drop shadow to distinguish the header from the table (they are the same color in this particular case).

I decided to subclass UIView and do the layout in IB.  This kept the code clean and was a BREEZE to lay out (and change layouts as we’ve now done several times).  Unfortunately, it wasn’t as straight-forward as I originally thought.  However, with a little help from Ray Wenderlich, I was able to get it implemented.  This is a quick tutorial for those out there that may be struggling with something similar.  The technique outlined below is only available for apps targeting iOS devices running at least 4.0.

Create the project

To get started, create a view based application – I named mine ReusableTableHeaders.  Within ReusableTableHeadersViewController.h, change the parent class from UIViewController to UITableViewController and define two instance variables – tblData (UITableView) and data (NSArray).  tblData will be our table view (so remember to add IBOutlet) and data will be a simple array of information to display.  Before leaving ReusableTableHeadersViewController.h, add UITableViewDelegate and UITableViewDataSource to the interface definition.

Pop over to the implementation file.  The first thing I always do is synthesize and update dealloc accordingly.  This tends to save me from myself later.  Within the viewDidLoad method, fill data with some values.  I went with the oh-so-clever ‘Value 1′, ‘Value 2′, and ‘Value 3′.  Once complete, open up IB and we’ll set the table view up before we build and run to make sure we’re ok.

Within IB, delete the UIView that’s currently there and replace it with a UITableView.  Connect that to both tblData and view within the File Owner.  You’ll also want to set the File Owner as the data source and delegate.  I changed my table view style to grouped and added a background.  That’s totally your call.

Here’s a quick shot of what IB looks like:

Build and Run to make sure we’re on the same page thus far.  Here’s a quick shot of what I get.

Subclassing UIView

Now that we have the foundation in place, let’s get started on the header view.  Add a new Objective-C class to your project.  When prompted to choose your type, you’ll also want to set the subclass option to UIView.  I named my class HeaderView. We’re going to go ahead and add a nib as well.  Add a new view based nib to your project – I named mine HeaderView.xib.

Once your class files and nib are created, define a UILabel instance variable within the .h (mine is titled lblTitle) and set it as an outlet.  Now, hop over to the implementation file, synthesize, and update the dealloc method.  Also, be sure to include <QuartzCore/QuartzCore.h>.  Within the initWithFrame method, add the following code:

The code is pretty straight-forward.  The first block loads the HeaderView nib file and sets this itself equal to the loaded nib.  The second block of code handles setting the drop shadow (note: the layer.shadow* related code only works in iOS 4.0 and above).  Manipulating the shadow color can produce some pretty cool effects but we’ll stick with the generic black for now.  With that done, it’s time to set our nib up in IB.

Setting up the view in IB

Unfortunately, and I’m not sure why, you can’t alter the height of the default view when creating a view based nib.  My solution, delete the existing view and add a new one.  Set your desired dimensions – for this tutorial we go with 320 by 60.  You’ll also want to drag another UIView and UILabel into the nib as subviews.  I actually added two UILabels – a ‘title’ label and the label I’ll update programmatically.

Select the top level view and open Inspector.  Set the class to your custom class – HeaderView.  While in the Inspector, set the background color clear.

Now select the UIView subview and change the height dimension to just slightly less than our ‘parent’ view.  For this tutorial, I went with a difference of 5 points – 320 by 55 – and then aligned the two UIViews at the top.  Change the background color to whatever you’d like your header to be.

Link up one of the UILabel’s to lblTitle you defined in HeaderView.h and you should be all set.

Using the view

First things first, import your custom class within ReusableTableHeadersViewController.  From here, you have several options about where to implement your custom view.  The requirement I needed to satisfy required that I use the viewWillAppear method as information could be updated as views pushed and popped.  I wanted to ensure I had the most up-to-date information presented.  For this tutorial, we’ll load it within viewDidLoad.

Walking through what we just did; we instantiate the view, set the title label, and then load it into our table view as the header.

Wrapping Up

And we’re done! Build and run and you should have something that resembles the screenshot below!

Here’s the project files:

Well, that’s my first iOS tutorial.  Hope it helps and be sure to let me know what works and what doesn’t work in the comments.  I hope to have several more over the course of the year.

Did you like this? Share it:



Google AdWords gets partial HTML5 makeover

It’s been a while since I’ve posted but I saw something this evening that I thought was worth posting.  I’ve been spending a lot of my free time lately developing and promoting an iPhone app.  I’ve got a second in process so this whole process has been a great learning experience.  Part of my mobile obsession extends to browser based apps (i.e. not App Store downloads) that utilize some of the advancements in the HTML5 specification (I use the word ‘specification’ loosely as I’ll include local storage, geolocation, etc under the same umbrella on this site).

HTML5 has it’s pro’s and con’s that each developer needs to weigh (we won’t get into that here) but web storage and web database are great advances.  The packaged modern mobile browsers (Safari, Android browser, etc) all support the specification which allows applications to store information from within their application that persists from session to session.  It can be very powerful…but it is definitely open for exploitation.  A common example is Gmail which utilizes the storage feature (along with App Cache) to allow you to work within the Gmail web-app while you are not connected to a network.  It also speeds up the entire user experience.

All that being said, I logged into AdWords this evening to begin preparing my campaign for this weekend and noticed they’ve begun utilizing local storage.  The great thing about it is that they request your approval rather than doing it behind the scenes.  Given that any website can create a ‘database’ on your local machine for storing information, I think that all user-agents (think Safari, Firefox, Chrome, etc) should force the user to authorize each use of local storage – i.e. one approval for

In short, it’s really cool that more and more sites are beginning to implement these features as browsers roll-out support but I’m more impressed that AdWords asks for permission.  I think more web-apps should follow the AdWords lead!

Did you like this? Share it:



Gone Mobile with WPtouch

The other day I read Justin Levy’s post on going mobile with WPtouch and just had to experiment.  I haven’t previously had a mobile specific version so it’s definitely an exciting move. Here’s a quick round up of my experience.


Installation was a breeze.  WPtouch is a WordPress plugin, all it took was downloading the files, uploading it to my server and activating it from the dashboard.  Once activated we were up-and-running with the vanilla install.  Now on to customizing…


WPtouch offers a wide array of customizing (sorry, this is a word I’ve gotten way too used to in the SAP world) options from enabling AJAX comment posting to custom CSS/Javascript inclusion.  I kept my install fairly simple but there were a couple things I changed.

  1. I call myself a developer so I went with a snazzy App Store icon as my mobile banner image (see end of the post). WPtouch has a pretty good selection of images although they’re mostly centered around the iPhone.  If nothing meets your needs you’re more than welcome to upload a custom file.
  2. Linking of my AdSense and Analytics accounts.  Must haves…AdSense to collect those occasional pennys and Analytics to obviously to continue to understand how people flow through the site.  Adding both was EXTREMELY easy to do with a custom section for each.

WPtouch gives you the option to display a ‘desktop’ (i.e. non-mobile) version of your website to users on their first visit and include the ability to toggle mobile vs. desktop in your theme footer.  I get the potential draw but if you’re going to go mobile, I’m not sure why you wouldn’t always default mobile and allow them to switch back if they want.

Anyways, you can also change what icon is used for each post and how much information about the post is shown (e.g. just the title, title and a teaser, tags, categories, etc).  I played with the settings a bit but I think that’s really more of a personal choice…at least until I get time to test and study analytic data.

Additions and Suggestions

For a donation supported plugin I can’t really complain.  It’s easy and relatively robust but there are still a couple things I would like to see enhanced:

  1. I understand it’s a mobile device and landscape is limited but a second ‘title’ (under below) would be ideal.  Obviously, each blog owner would need to be smart about how it was used.
  2. Better AdSense rendering.  This may be slightly out of the WPtouch developers hands but I noticed that AdSense ads show up very boxy compared to the smooth WPtouch design.  I don’t know if that’s anything they can fix or perhaps me just being new to AdSense mobile but it didn’t exactly flow together.

If you’re mobile version is powered by WPtouch leave a comment and let me know what you think!  Finally, here’s a fullscreen shot of…the mobile version…from my iPhone.

Did you like this? Share it:



My Resolutions for 2010

I’ve been kicking around the idea of publishing my personal resolutions for 2010 for a couple weeks and just decided to pull the trigger.  My thoughts, what better way of pushing myself to follow through than to publish them on the web for all to see.  I’ll try to take a couple checkpoints throughout the year to let you know how I’m progressing.

So, without further ado, here are my resolutions for 2010:

  1. Develop and iPhone app.  I have a few ideas but I won’t reveal those just yet.  Look out for the announcement when the app is ready though :)
  2. Blog more – 3-4 times per month is my target.  I plan on blogging about my iPhone development experience as well as about some topics I’ve been hoarding from my day job on implementing SAP SRM 7.0.
  3. Clean up my resume and create a web-ready version (linked on this blog obviously).
  4. Develop a new website – I suspect this will likely be to complement the iPhone app but I would like to build a custom WordPress theme for
  5. Reach 500 followers and 1,500 tweets on Twitter.  I hover between 140 and 150 followers and just hit 600 tweets today.
  6. Exercise more – 4-5 times per week.  Throughout the last couple years I have been working out 2-4 times a week but I would like to raise the bar a bit at 4 to 5 times to help get in better shape and shed a few pounds.
  7. Lower my golf score.  Notice I didn’t say handicap there :) .  Over the last few years I’ve only been able to play a couple times a year because work has consumed so much of my time.  My goal for 2010 is to play more and get my average score consistently in the 90′s (high 90′s is ok by me for this year).

I wanted to list 10 (for some reason that sounded like such a nice, even number) but this is all I could muster today.  If I manage to achieve all of this with time to spare in 2010 (unlikely, unless you find me a new job)…I’ll add a couple more.

By the way, how does everyone feel about the fact that years will now almost always be prefaced with ‘twenty’ instead of ‘two-thousand’?!?

Did you like this? Share it: