Recently I was working on optimizing a part of the code, where we create a formatter, cache it and then use this formatter hundreds of time.
This is a pretty harmless piece of code where you basically create a formatter, and then cache it. We retrieve the formatter from the cache using a key and save it in the cache. I extracted the stack trace from instruments. This is as shown below.
Seems like there is something fishy going on. If you look closely at the arrow, you can see there is a regenerate method being called. Let’s dig in more closely. You can go into the source code by clicking on the row.
We are seeing that a simple locale assignment is taking around 29.00ms. This is fast, but not really fast, when you look at the whole method. Now I am curious. I try to dig in to the method called _regenerateFormatter
In order to know the implementation, I look into the source code here. Its pretty old, but the calls remain pretty much the same.
The setLocale is calling a method called [self _reset]
The reset method, resets the formatter and calls regenerate. The culprit seems to be the recreation of the formatter. The regenerate method basically checks for each and every attribute and then recreates the formatter.
There you go, now we know why the formatter is taking time. In order to fix this, we should set the locale when the formatter is being created, and not outside the if loop. This will save us time.
formatter = NumberFormatter()
if accuracyType == .byFraction {
formatter?.maximumFractionDigits = maxDigit
formatter?.minimumFractionDigits = minDigit
} else if accuracyType == .bySignificant {
formatter?.minimumSignificantDigits = minDigit
formatter?.maximumSignificantDigits = maxDigit
}
formatter?.roundingMode = roundMode
formatter?.usesGroupingSeparator = usesGroup
formatter?.numberStyle = numberStyle
formatter?.locale = locale
Hopefully this tutorial helps.
Leave a Reply