6

If you have code such as this, then p will be "2.99":

let price = 2.99
let p = String(format: "%.2f", price)

However, if you have code like this:

let priceNS: NSDecimalNumber = 2.99
let p2 = String(format: "%.2f", priceNS)

Then p2 is "0.00".

How can you format an NSDecimalNumber into a string like this? (NSDecimalNumber is how the price in an SKProduct is stored)

pkamb
  • 33,281
  • 23
  • 160
  • 191
Gruntcakes
  • 37,738
  • 44
  • 184
  • 378

2 Answers2

6

You should format your product price using NumberFormatter and use your product locale: https://developer.apple.com/documentation/storekit/skproduct/1506094-price

let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency 
numberFormatter.locale = someSKProduct.priceLocale
let formattedPrice = numberFormatter.string(from: someSKProduct.price) ?? ""
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • `SKProduct` really contains a "price locale" instead of a currency code? That's pretty weird. The product shouldn't determine if e.g. I use `.` or `,` for the decimal separator. – Lily Ballard Oct 03 '17 at 23:28
  • @KevinBallard I don't think thats a problem considering that the user doesn't need to input any price. – Leo Dabus Oct 03 '17 at 23:30
  • It affects display, not input. If the user has their device set to French, and is purchasing something in USD, it should show up as e.g. `2,99 $US`. But if the `product.priceLocale` is `en_US` and you set that on the formatter, they'll see `$2.99` instead of `2,99 $US`. – Lily Ballard Oct 03 '17 at 23:33
  • It will always display using the locale from where the App is being bought. If I buy a product here in Brazil from US AppStore it will display `$0.99` not `R$0,99` – Leo Dabus Oct 03 '17 at 23:37
  • @KevinBallard "French" isn't a locale. Do you mean a locale of `fr_FR`, `fr_CA`, `fr_US`, or one of many other possibilities? The language part of the locale will have no real affect on the output of a currency value. It's the region part of the locale that matters. Either way, the `priceLocale` of the product should be appropriate for the user's device and the product's currency. – rmaddy Oct 03 '17 at 23:41
  • True, I used "French" as shorthand for `fr_FR`. In any case, it's certainly possible for `priceLocale` to be something like `fr_FR@currency=USD`, but if that's what it is, then why is it exposed as a locale at all instead of just a currency code? – Lily Ballard Oct 03 '17 at 23:44
2

You can use a NumberFormatter to convert an NSNumber to a String.

let priceNS:NSDecimalNumber = 2.99
let nf = NumberFormatter()
nf.maximumFractionDigits = 2
nf.string(from: priceNS) //2.99
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Using the `.currency` style is only appropriate if you want the currency symbol (e.g. `$`) to show up. If you do, leave the locale alone and set the `currencyCode` property instead. – Lily Ballard Oct 03 '17 at 22:40
  • Depends on how the price is being shown. Maybe OP is already showing it in a context where the user knows the currency? – Lily Ballard Oct 03 '17 at 22:43
  • In any case, to expand on my previous comment, the locale affects formatting, and the `currencyCode` affects the actual currency. Don't set the locale just to force USD, that will not work properly. Besides formatting differences, this will make it show up as e.g. `$2.99` in Canada when it should be showing up as `US$2.99`. If you leave the locale alone and set `nf.currencyCode = "USD"` then you'll get the correct currency display regardless of user locale. – Lily Ballard Oct 03 '17 at 22:44