In a current project I’m working on we’re making heavy use of NSDateFormatter.  Here’s a quick tip about how to make life with NSDateFormatters easier.

Firstly, let’s cover some basics on NSDateFormatter:

  • NSDateFormatters are commonly used for conversion to and from an NSString from/to an NSDate
  • Allocation of NSDateFormatters is expensive – if you use them in tableView:cellForRowAtIndexPath you’re going to notice this…
  • Use of NSDateFormatters is cheap once they’re instantiated and set up

So, this leads to a fairly typical, but somewhat verbose pattern:

    static NSDateFormatter *dateFormattter = nil;
    if (dateFormattter == nil)
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            dateFormattter = [[NSDateFormatter alloc] init];
            dateFormattter.dateStyle = NSDateFormatterShortStyle;
            dateFormattter.doesRelativeDateFormatting = YES;
        });
    }

There’s a lot of boilerplate here, and it’s not particularly clean or meaningful.  We could write a Code Snippet to help us here, but that wouldn’t help with the semantic value and there’s something we can do better.

Also, a lot of times we’ll find the same dateFormatter needed in different locations – e.g. a method converting Strings to Dates and another method converting them back.  We could create an instance variable to hold a single date formatter, allocate on demand, but then our boilerplate Code Snippet is no longer helpful…  So let’s solve both these problems with a handy category.

Introducing: NSDateFormatter+IkuramediaLazyFormatter

My quick solution was to create an NSDateFormatter category, with supporting Code Snippets.  Let’s look at the two method signatures this category adds:

/***
 Snippet: IMKeyedLazyFormatter

 NSDateFormatter *dateFormatter = [NSDateFormatter lazyDateFormatterWithKey:<#Key#>
 configurationBlock:^(NSDateFormatter *dateFormatter)
 {
    <#code#>
 }];
 ***/

+ (NSDateFormatter *)lazyDateFormatterWithKey:(NSString *)key
                          configurationBlock:(IMLazyDateFormatterBlock)configurationBlock;

/***
 Snippet: IMLazyFormatter

 static IMLazyDateFormatterToken dateToken;
 NSDateFormatter *dateFormatter = [NSDateFormatter lazyDateFormatterWithToken:&dateToken
                                    configurationBlock:^(NSDateFormatter *dateFormatter)
                                    {
                                        <#code#>
                                    }];
 ***/

+ (NSDateFormatter *)lazyDateFormatterWithToken:(IMLazyDateFormatterToken __strong*)token
                             configurationBlock:(IMLazyDateFormatterBlock)configurationBlock;

We have two methods, to support the different use-cases:

  • Lazy Instantiation of NSDateFormatter – use lazyDateFormatterWithToken:configurationBlock
  • Usage of an NSDateFormatter in multiple locations – use lazyDateFormatterWithKey:configurationBlock, making sure to use the same key and configuration block in each location that you need this.

We introduce the IMLazyDateFormatterBlock type for the configurationBlock, passing in the dateFormatter as a parameter.  This block is executed once only, on first instantiation.  For the simple Lazy Instantiation case we also introduce the IMLazyDateFormatterToken type – this is simply an NSString pointer, but we use it in a write-back fashion in order to ensure we get the same date formatter back each time.  The code snippet shows a static token being used, this is allocated on the heap, but allows our category to keep track of a larger object (the NSDateFormatter).  In a future version we could upgrade the Category to support on-demand caching and invalidation of previously allocated NSDateFormatters to keep our memory footprint down – but it’s unlikely this will be necessary in most projects.

The code is available as a gist on github – and in the public domain – let us know in the comments if you find this useful or use it in your apps though!

About ikuramedia

ikuramedia - The App Specialists www.ikuramedia.com

What do you think?