How to format Decimal in Swift 3
Asked Answered
P

1

7

I'm trying to use the Swift Decimal Structure for currency operations but I cannot format it.

How can I format var myDecimal:Decimal = 9999.99 to display $9,999.99?

Without using Decimals I can do it as follow...

let myTotal:NSNumber = 9999.99

let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true

currencyFormatter.numberStyle = .currency
currencyFormatter.locale = NSLocale.current
let priceString = currencyFormatter.string(from: myTotal)

myLabel.text = priceString

This works fine but I have been reading and Decimalseem to be the right type for currency.

I tried...

let myTotal:Decimal = 9999.99

let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true

currencyFormatter.numberStyle = .currency
// localize to your grouping and decimal separator
currencyFormatter.locale = NSLocale.current
let priceString = currencyFormatter.string(from: NSNumber(myTotal))

myLabel.text = priceString

... but I get error

Argument labels '(_:)' do not match any available overloads

What is the right way to format Decimals in Swift?

Poorhouse answered 8/9, 2017 at 0:49 Comment(8)
Just use string(for: myTotal) instead of string(from:Ahmednagar
Check this #29783482Ahmednagar
I don't think you'll see any benefit from using Decimal over Float or Double unless you need high precision, which is unlikely for currency.Bioplasm
@LeoDabus string(for: myTotal) did the trick. Thanks.Poorhouse
@DaveWood - What would you considered high precision, when would you use Decimal?Poorhouse
@Poorhouse High precision is needed for things like 3D graphics, where you can have lots of digits after the decimal point. If you're only using 2 decimal places, you can avoid complicating your code and just use Floats.Bioplasm
@Poorhouse you are welcome. Note that the currencyField of the linked question can be used with any currency including the ones that doesn't have any fraction digits at all.Ahmednagar
Never use float or double for currency. See #3730519Cognoscenti
W
9

You can just cast your Decimal to an NSDecimalNumber first:

let priceString = currencyFormatter.string(from: myTotal as NSDecimalNumber)

Wichman answered 8/9, 2017 at 1:10 Comment(4)
string(from:) is more specific, since it takes a number type as an argument rather than Any.Wichman
NSDecimalNumber is an NSNumber type.Wichman
string(for:) is a method on the abstract Formatter superclass. It is a nonspecific API that applies to any Formatter subclass, and the documentation says nothing about what it does when used on a NumberFormatter instance. string(from:) is actually mentioned in the NumberFormatter documentation, and what it does is actually documented. Therefore, I prefer it. In practice, it probably doesn't strictly matter since in all likelihood, one of these methods probably just calls through to the other.Wichman
They used Any because the method is on the abstract superclass, Formatter, and thus has no idea what types of objects it's going to take, or even whether it's a number formatter, date formatter, a person name formatter, some crazy custom formatter, or something else. They actually did add a method for each type Double, Float, Decimal, in a sense, because they added a method for NSNumber, which is the Objective-C type that all those types bridge to.Wichman

© 2022 - 2024 — McMap. All rights reserved.