Is caching a NSDateformatter application-wide good idea? Is caching a NSDateformatter application-wide good idea? ios ios

Is caching a NSDateformatter application-wide good idea?


I'll chime in here with an answer based on experience. The answer is yes, caching NSDateFormatter app-wide is a good idea, however, for added safety there is a step you want to take for this.

Why is it good? Performance. It turns out that creating NSDateFormatters is actually slow. I worked on an app that was highly localized and used a lot of NSDateFormatters as well as NSNumberFormatters. There were times that we dynamically created them greedily within methods as well as having classes that had their own copy of the formatters they needed. In addition, we had the added burden that there were cases where we could also display strings localized for different locales on the same screen. We were noticing that our app was running slow in certain cases, and after running Instruments, we realized it was formatter creation. For example we saw performance hit when scrolling table views with a large number of cells. So we ended up caching them by creating a singleton object which vended the appropriate formatter.

A call would look something like:

NSDateFormatter *dateFormatter = [[FormatterVender sharedInstance] shortDate];

Note, this is Obj-C, but the equivalent can be made in Swift. It just happened ours was in Obj-C.

As of iOS 7, NSDateFormatters and NSNumberFormatters are "thread safe", however as Hot Licks mentioned, you probably don't want to go around modifying the format if another thread is utilizing it. Another +1 for caching them.

And another benefit I just thought of was code maintainability. Especially if you have a large team like we have. Because all devs know there is a centralized object that vends the formatters, they can simply see if the formatter they need already exists. If it doesn't, it gets added. This is typically feature related, and hence usually means that new formatter will be needed elsewhere as well. This also helps reduce bugs, because if there happens to be a bug in the formatter, you fix it one spot. But we usually catch that during the unit tests for the new formatter.

There is one more element you can add for safety, if you want. Which is you can use the NSThread's threadDictionary to store the formatter. In other words, when you call the singleton which will vend the formatter, that class checks the current thread's threadDictionary to see if that formatter exists or not. If it exists, then it simply returns it. If not, it creates it and then returns it. This adds a level of safety so if, for some reason you wanted to modify your formatter, you can do it and not have to worry about that the formatter is being modified by another thread.

What we used at the end of the day was singleton which vended specific formatters (both NSDateFormatter and NSNumberFormatter), ensuring that each thread itself had it's own copy of that specific formatter (note the app was created prior to iOS 7, which made that an essential thing to do). Doing that improved our app performance as well as got rid of some nasty side effects we experienced due to thread safety and formatters. Since we have the threadDictionary part in place, I never tested it to see if we had any issues on iOS7+ without it (ie. they have truly become thread-safe). Thus why I added the "if you want" above.


Since Swift uses dispatch once methods for static properties creation it's really fast and safe to create DateFormatter in a such way.

extension DateFormatter {    static let shortFormatDateFormatter: DateFormatter = {        let formatter = DateFormatter()        formatter.dateFormat = "yyyy-MM-dd"        formatter.locale = Locale(identifier: "en_US_POSIX")        return formatter    }()}

Than just write

date = DateFormatter.shortFormatDateFormatter.string(from: json["date"])


In my opinion Caching NSDateFormatter is a good idea if your app is using that widely or through-out your app, it'll increase the performance of your app. If you need that in 1 or 2 places, it won't be a good idea. However changing the date format is not a good idea, it can lead you into undesired situations. (You need to keep track the current format each time before going to use it)

In one of my application I used a singleton with three date format objects(all three contains three different formats) as properties. And custom getters for each NSDateFormatter

+ (instancetype)defaultDateManager{    static DateManager *dateManager = nil;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        dateManager                = [[DateManager alloc] init];    });    return dateManager;}// Custom Getter for short date- (NSDateFormatter *)shortDate{    if (!_shortDateFormatter)    {        _shortDateFormatter = [[NSDateFormatter alloc] init];        [_shortDateFormatter setDateFormat:@"yyyy-MM-dd"]    }    return _shortDateFormatter}

Like this I implemented custom getters for the other two also.

Why I implemented custom getters ? Why I didn't allocate the NSDateFormatter during singleton initialization ?

It's because I don't want to allocate them in the beginning itself. I need to allocate it when it's needed for the first time (On a On Demand basis). In my app the all three NSDateFormatters are not widely used, that's why I chose such a pattern for implementing it. (My app is in Objective C, that's why I used the Objective C code here)


matomo