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