Skip to main content

How to Cache NSDateFormatter?

Instantiating NSDateFormatter objects is slow. Most well-written apps that use NSDateFormatter will make efforts to reduce the number unique instances created. Using a static property is sufficient for most cases, but what if you work on a large app where lots of NSDateFormatter objects are needed by a large number of classes. Wouldn’t it be nice if there was an NSCachedDateFormatter that keeps track of what it has instantiated and will return cached objects and only instantiate new ones when necessary? Wouldn’t it be nice if NSCachedDateFormatter was a singleton and could be used app-wide? Here's a sample class that can be used to fulfill this need.

class CachedDateFormatter {
    static let sharedInstance = CachedDateFormatter()
    var cachedDateFormatters = [String: NSDateFormatter]()

    func formatterWith(#format: String, timeZone: NSTimeZone = NSTimeZone.localTimeZone(), locale: NSLocale = NSLocale(localeIdentifier: "en_US")) -> NSDateFormatter {
        let key = "\(format.hashValue)\(timeZone.hashValue)\(locale.hashValue)"

        if let cachedDateFormatter = cachedDateFormatters[key] {
            return cachedDateFormatter
        }
        else {
            let newDateFormatter = NSDateFormatter()
            newDateFormatter.dateFormat = format
            newDateFormatter.timeZone = timeZone
            newDateFormatter.locale = locale
            cachedDateFormatters[key] = newDateFormatter
            return newDateFormatter
        }
    }
}

Use the CachedDateFormatter singleton to instantiate any NSDateFormatter object you need. The formatterWith function returns a NSDateFormatter object and stores it in a dictionary based on format string, time zone and locale for future use. If another part of the app needs a date formatter with those same values it’ll get the cached version.

Usage from Swift

let dateFormatter = CachedDateFormatter.sharedInstance.formatterWith(format: "yyyy-MM-dd'-'HHmm", timeZone: NSTimeZone.localTimeZone(), locale: NSLocale(localeIdentifier: "en_US"))

Since Swift allows for default argument values you can omit the second and/or third argument. A minimum call that defaults to the local time zone and “en-US” locale would look like…

let dateFormatter = CachedDateFormatter.sharedInstance.formatterWith(format: "yyyy-MM-dd'-'HHmm")

Usage from Objective-C

Objective-C doesn’t support the concept of optional arguments so it must always be called with all three arguments in Objective-C.

NSDateFormatter *dateFormatter = [[CachedDateFormatter sharedInstance] formatterWithFormat:@"yyyy-MM-dd'-'HHmm" timeZone:[NSTimeZone defaultTimeZone] locale:[NSLocale localeWithLocaleIdentifier:@"en-US"]];

It might be overkill for smaller apps but could come in handy for larger code bases. 

Here's an app on the App Store that makes use of the teachings here:

Comments

Popular posts from this blog

Integrating SwiftUI into Existing AppKit Cocoa Projects: A Step-by-Step Guide

As Apple continues to push SwiftUI as the future of app development across its platforms, many developers find themselves in a position where they need to integrate this modern framework into their existing AppKit Cocoa projects. This integration can breathe new life into older applications, allowing developers to take advantage of SwiftUI's declarative syntax and powerful features while maintaining their existing codebase. In this guide, we'll walk through the process of adding SwiftUI to an existing AppKit Cocoa project, providing you with the knowledge to modernize your macOS applications.

Tips to improve performance of database-driven Java applications

Here are four tips, not really super cool or something you never heard and I rather say fundamentals but in practice many programmers  just missed these, you may also called this database performance tips but I prefer to keep them as Java because I mostly used this when I access database from Java application. Java database performance tips 1: Reduce the number of calls you make to the database server. Believe it or not if you see performance in seconds than in most cases culprit is database access code. since connecting to database requires connections to be prepared, network round trip and processing on database side, its best to avoid database call if you can work with cached value. even if your application has quite dynamic data having a short time cache can save many database round trip which can boost your java application performance by almost 20-50% based on how many calls got reduced. In order to find out database calls just put logging for each db call in DAO layer, e...

How to Use OUIEditableFrame with the OmniGroup Framework

TLDR: This blog post provides a detailed tutorial on how to implement OmniGroup’s OUIEditableFrame in an iOS project to render text with proper kerning, which cannot be achieved with standard UIKit controls due to a bug. The guide walks through creating and configuring an Xcode workspace, cloning the OmniGroup project from GitHub, adding necessary frameworks and dependencies, and writing the required view controller code. Learn to implement OmniGroup's OUIEditableFrame for proper text kerning in iOS projects with this step-by-step Xcode tutorial. Table of Contents: Introduction Create and Configure Xcode Workspace Clone the OmniGroup Project from GitHub Add the FixStringsFile Project Add OmniBase Add the Rest of the Frameworks Write View Controller Code Making It Work in iOS 5 Get Rid of the Static Analyzer Message If you need a UITextField that renders text with proper kerning you don’t have many of options. Writing al...