NumberFormatter padding differently in 13.1?

Here is some sample code that behaves differently under iOS 12 and earlier vs 13.1/13.2b. Previously, we would get "EUR100.00" but now we get "EUR 100.00" where the space is a non-breaking space.


Why was this changed? How can we get consistent behavior from NumberFormatter?


  let numberFormatter = NumberFormatter()

  let currencyID = "EUR"

  let locale = Locale(identifier: "en_US")

  numberFormatter.formatterBehavior = .behavior10_4
  numberFormatter.generatesDecimalNumbers = true
  numberFormatter.minimumFractionDigits = 2
  numberFormatter.maximumFractionDigits = 2

  numberFormatter.currencyCode = currencyID
  numberFormatter.locale = locale

  numberFormatter.numberStyle = .currency

  let symbol = "EUR"

  numberFormatter.currencySymbol = symbol
  numberFormatter.internationalCurrencySymbol = symbol

  let number = NSDecimalNumber(integerLiteral: 100)

  let result = numberFormatter.string(from: number)

  print("\(String(describing: result))")

To work around these breaking changes in major OS updates, it's best to encapsulate the concept of money and currency into your own objects (this comes from 11 years writing iOS financial apps). Using "en_US_POSIX" seems to be the most compatible across major OS updates. I've encapsulated this logic here: https://github.com/electricbolt/corekit. Check the MoneyFormatter class.

If you use the real symbol


let symbol = "€"


then you get

€100.00


So, it is apparant they changed

Eur100.00

to

Eur 100.00


for better readability


If you really need the previous behavior, just replace char:


let resultEur = numberFormatter.string(from: numberEur)?.replacingOccurrences(of: " ", with: "")
print("\(String(describing: resultEur!))")


where " " holds the non-breaking space.


That will change nothing in iOS12, but strip the non breaking space in iOS 13.


You can also wrap it in an extension for easier use later:


extension String {
    var stripped: String {
        return self.replacingOccurrences(of: " ", with: "")
    }
}


let resultEur = numberFormatter.string(from: numberEur)?.stripped
print("\(String(describing: resultEur!))")

How can we get consistent behavior from

NumberFormatter
?
NumberFormatter
, and it’s friends, most notably
DateFormatter
, are strongly focused on creating user-displayable strings. As such, you should expect some variability in the exact format of the string returned. The expected use case is for you to take the string returned by the formatter and put it on screen, in which case differences like this don’t matter.

If you’re using the string in a place where such differences do matter, that’s likely to cause you long-term grief. The best way to avoid that grief depends on your specific requirements. Can you explain more about what you’re doing with this result?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
NumberFormatter padding differently in 13.1?
 
 
Q