Search code examples
swiftinitialization

How to add custom init for String extension?


How can I add custom init method for String extension?

extension String {
    init(_ amount: Double, decimalPlaces: UInt) {
        self.init()
        let decimalFormat = "%0.\(String(decimalPlaces))f"
        let currencyAmount = String(format: decimalFormat, amount)
        let currencySign = NSLocalizedString("Defaults.CurrencySign", comment: "currency sign")
        let formattedString = "\(currencySign)\(currencyAmount)"
        // How to set self to `formattedString` ?
    }
}

As result I want to see something like this:

let price = Double(155.15)
let formattedPrice = String(price, decimalPlaces: 2) // formattedPrice = "$155.15"

UPDATED: Final solution

extension String {
    init?(currencyAmount: Double) {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale(identifier: NSLocalizedString("Defaults.LocaleCurrencyFormat", comment: "currency sign")) // Defaults.LocaleCurrencyFormat equal "es_US" for US
        let formattedAmount = formatter.string(from: NSNumber(value: currencyAmount)) ?? ""
        self.init(formattedAmount)
    }
}

Solution

  • Edit: Don't format currencies yourself.

    However you might think currencies are formatted, you're almost certainly wrong. Just compare:

    • US/Canada: $3,490,000.89
    • French Canadian: 3 490 000,89 $
    • France: 3 490 000,89 €
    • Germany: 3.490.000,89 €

    Instead, use NumberFormatter with numberStyle set to .currency, with a specified locale.

    let currencyFormatter = NumberFormatter()
    currencyFormatter.usesGroupingSeparator = true
    currencyFormatter.numberStyle = .currency
    currencyFormatter.locale = Locale.current
    let priceString = currencyFormatter.string(from: 9999.99)!
    print(priceString) // Displays $9,999.99 in the US locale
    

    Original answer:

    The initializers (and mutating methods) of value types can simply assign directly to self:

    import Foundation
    
    extension String {
        init(_ amount: Double, decimalPlaces: UInt) {
            let currencyAmount = String(format: "%\(decimalPlaces).f", amount)
            let currencySign = NSLocalizedString("Defaults.CurrencySign", comment: "currency sign")
            self = "\(currencySign)\(currencyAmount)"
        }
    }
    
    let price = Double(155.15)
    let formattedPrice = String(price, decimalPlaces: 2) // formattedPrice = "$155.15"