How to Use NumberFormatter (NSNumberFormatter) in Swift to Make Currency Numbers Easy to Read

NSNumberFormatter Currency Price String in Swift

When you display a number in Swift (Float, Double, Int) it will display without grouping separators. By default a number like 4,592,028.0 will display like: 4592028.0 You need to use the NumberFormatter (NSNumberFormatter) class to convert your number into a pretty String for a text field.

To display currency, you will need to show the currency symbol ($, €, ¥, £) for the current locale.

Displaying the correct currency symbol can get complex pretty quickly – thankfully, Apple has you covered and provides a solution with the NSNumberFormatter, now NumberFormatter class.

NSNumberFormatter Is Now NumberFormatter in Swift 4

In Swift 4 many of these API's renamed, so I'll share the Swift 2 code, as well as the updated Swift 4 code.

NumberFormatter will show the correct symbol, and the formatting that you might not realize is very different from what you're used to. Different countries use different decimal separators and grouping separators—take a look!

  • In the USA: $3,490,000.89
  • In France: 3 490 000,89 €
  • In Germany: 3.490.000,89 €

You don't have to memorize these currency symbols, grouping separators, or decimal separators. Apple has done all the heavy lifting with NumberFormatter.

The following code sample will use the current locale of the user's device to format the currency:

Swift 4+

let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
// localize to your grouping and decimal separator
currencyFormatter.locale = Locale.current

// We'll force unwrap with the !, if you've got defined data you may need more error checking
let priceString = currencyFormatter.string(from: 9999.99)!
print(priceString) // Displays $9,999.99 in the US locale

Swift 2

var currencyFormatter = NSNumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle 
// localize to your grouping and decimal separator
currencyFormatter.locale = NSLocale.currentLocale()
var priceString = currencyFormatter.stringFromNumber(9999.99)
print(priceString) // Displays $9,999.99 in the US locale

NumberFormatter can use the correct separators and currency symbols for your country by setting the Locale directly.

Forcing a Custom Locale

You can override the users locale to display specific currency formats by changing the Locale using the identifier.

currencyFormatter.locale = Locale(identifier: "fr_FR")
if let priceString = currencyFormatter.string(from: 9999.99) {
    print(priceString) // Displays 9 999,99 € in the French locale
}

currencyFormatter.locale = Locale(identifier: "de_DE")
if let priceString = currencyFormatter.string(from: 9999.99) {
    print(priceString) // Displays 9.999,99 € in the German locale
}

More Locale Identifier Codes

Download the Swift Playgrounds for NumberFormatter

I've got more examples that you can explore to play with the NumberFormatter Playgrounds file.

Download the currency Playgrounds file and you can learn how to programmatically set the NSLocale to the German, French, and US English.

Homework

Try changing the NumberFormatter's groupingSeparator, currencyGroupingSeparator, and related properties to format both decimal style numbers and currency style numbers.

Read the documentation for NumberFormatter and experiment with changing how it formats your decimal numbers (i.e. try different grouping separators like: "_" or "*").

How to Get UITextField Text Editing Changed Events for User Input Validation - Swift Tips 1

Do you need to get user input from your UITextField change events as your user types in a text field? Are you trying to validate text to hide or show a status message? In this tutorial you'll learn how to work with text change events in Swift as your user types in a text field.

You might have tried to use the UITextFieldDelegate only to find it's the wrong place to look.

You need to setup the Target/Action for the UITextField Editing Changed event (not to be confused with the Value Changed event).

Swift 4 and Xcode 9 Breaking Changes

Swift has evolved over the years, and I'll share some advice if your updating an app from Swift 2.

The Target/Action method names have changed in Swift 3, more details down below.

Xcode Project

Download the Xcode project from the free Swift Tips Course

UITextField Text Editing Changed Tutorial

Watch the updated tutorial on using Swift 4 and Xcode 9, and you'll see how to hook up the UI properly.

1 - Make a UITextField connection from UI to code

In the Assistant Editor (Venn Diagram icon in the top right) you need to drag an Action connection from your UI to your code. You can right-click or two-finger click on the trackpad and drag.

 

  1. Right-click and drag from the UITextField to your ViewController.swift code file
  2. Change the dropdown from Outlet to Action.
  3. Choose Editing Changed
  4. Type a method name: textFieldEditingDidChange

2 - Connect Outlets for the text field

Drag over connections for the UITextField, and you can use the textField.text property to get it’s value.

@IBOutlet weak var button: UIButton!
@IBOutlet weak var textField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    // disable button
    button.isEnabled = false
}

3 - Validate the input as the user types in the UITextField

You can print out the text as the user types it for testing. 

Your app logic should do some kind of validation, which you can refactor into it’s own method called validatePassword().

As a simple example, just enable or disable the button based on your validation logic, and you can make sure it works.

@IBAction func textFieldEditingDidChange(_ sender: Any) {
    print("textField: \(textField.text!)")

    if validatePassword(textField.text!) {
        // correct password
        button.isEnabled = true
    } else {
        button.isEnabled = false
    }
}

func validatePassword(text: String) -> Bool {
    var result = false
    // test password
    if text == "Secret!" {
        result = true
    }
    return result
}

@IBAction func buttonPressed(_ sender: Any) {
  print("You may enter")
  view.backgroundColor = UIColor.green
}

Swift 4 and Xcode 9 Breaking Changes

If you're running into crashes with typing old Swift code in Xcode 9, or you can't figure out why an old Swift 2 project isn't working it's most likely because Apple changed the naming convention for functions in Swift 3. And if you're following old code, you'll run into lots of errors trying to get it to work.

You'll see errors like this one:

2018-03-13 10:50:31.696398-0400 TextFieldChanged[44045:8613229] -[TextFieldChanged.ViewController textFieldEditingDidChange:]: unrecognized selector sent to instance 0x7ff76e41cd20

2018-03-13 10:50:31.702694-0400 TextFieldChanged[44045:8613229] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TextFieldChanged.ViewController textFieldEditingDidChange:]: unrecognized selector sent to instance 0x7ff76e41cd20'

change your selector code from Swift 2 code to be Swift 4+ compatible.

Swift 3 changed this in Swift Evolution 0046 and unfortunately it's a breaking code change that will cause a lot of crashing if you don't get it right.

// Swift 2

@IBAction func textFieldEditingDidChange(sender: AnyObject)
@IBAction func buttonPressed(sender: AnyObject)

// Swift 4

@IBAction func textFieldEditingDidChange(_ sender: Any)
@IBAction func buttonPressed(_ sender: Any)

1. In the past the first parameter label "sender" had been optional for single parameter methods, but now it's required, so that means all function signatures have changed to use `_` for an unnamed parameter.

2. You'll also see `AnyObject` is now `Any`.

Making these two changes will make your selectors work again.

Programmatically Add Selectors for UITextFieldChanged Events 

The code to work with selector's has changed from Selector("buttonPressed") to #selector(buttonPressed) in Swift 3+ from Swift Evolution 0022.

Here's the old syntax and the new syntax. And if the first parameter is un-named, you can omit the parenthesis.

// Swift 2
textField.addTarget(self, action: Selector("textFieldEditingDidChange:"), for: UIControlEvents.editingChanged)

// Swift 4 (you can omit the parenthesis)
textField.addTarget(self, action: #selector(textFieldEditingDidChange), for: UIControlEvents.editingChanged)

// Swift 4 (you can specify the parameters using (_:) since the label is now _ in Swift 4)
textField.addTarget(self, action: #selector(textFieldEditingDidChange(_:)), for: UIControlEvents.editingChanged)

Watch How to Validate Text in a UITextField

How to remove an array of objects from a Swift 2 Array - removeObjectsInArray

removeObjectsInArray Swift Protocol Extension.png

I was working on a game project in Swift and I wanted to remove objects from an Array, only to discover that my goto method from Objective-C’s NSMutableArray (removeObjectsInArray:) didn’t exist.

Removing multiple objects from an Array takes multiple steps – when you iterate over an Array you cannot remove objects. It’s a two step process, you need to discover which objects need to be removed and then you need to iterate through that list and remove each one, one at a time.

The code has changed between Swift 1.2 and Swift 2 – I’ll include both to show the differences.

Swift 1.2 Remove Multiple Objects from an Array

You can start by creating an array of objects – add to the end with append() or insert() at a specific index.

Next you will need to search for something in your Swift Array – for this example you’ll look for words with a specific letter. 

Lastly you’ll need to remove each word that contains the letter one at a time, outside of your first loop.

// Swift 1.2
var wordArray = ["Apple", "Carrot", "Peanut Butter"]
wordArray.append("Hummus")
wordArray.insert("Greek Salad", atIndex: 0)

// Find the objects to remove
var wordsToDelete: [String] = [String]()
for word in wordArray {
    if contains(word.lowercaseString, "p") {
        wordsToDelete.append(word)
    }
}

// Find the index and remove each object
for word in wordsToDelete {
    if let index = find(wordArray, word) {
        wordArray.removeAtIndex(index)
    }
} 

Swift 2 Remove Multiple Objects from an Array

Swift 2 changes the contains() function to a contains() method using Protocol Extensions and since we’re working with Swift 2 Strings – the character property needs to be used.

The global find() function is now replaced by the new indexOf() method on Array (technically CollectionType).

// Swift 2
var wordArray = ["Apple", "Carrot", "Peanut Butter"]
wordArray.append("Hummus")
wordArray.insert("Greek Salad", atIndex: 0)

// Find the objects to remove
var wordsToDelete: [String] = [String]()
for word in wordArray {
    if word.lowercaseString.characters.contains("p") {
        wordsToDelete.append(word)
    }
}

// Find the index and remove each object
for word in wordsToDelete {
    if let index = wordArray.indexOf(word) {
        wordArray.removeAtIndex(index)
    }
} 

 

Swift 2 Array Protocol Extension removeObjectsInArray

With the basics of removing objects from an Array you can take it a step further to get back to a single line of code to remove objects.

Using an extension in Swift 2 allows you to add functionality that’s missing from the Array type. An Array is a structure, so you’ll have to use the mutating keyword and the Element is the type of object that is in the Array (generics).

Equatable means that the type must support the == (equal to) method, which is required to find an object. String objects are already equatable, so you don't need to do any extra work. If you are storing a custom object you will need to implement your own isEqual method.

// Swift 2 Array Extension
extension Array where Element: Equatable {
    mutating func removeObject(object: Element) {
        if let index = self.indexOf(object) {
            self.removeAtIndex(index)
        }
    }
    
    mutating func removeObjectsInArray(array: [Element]) {
        for object in array {
            self.removeObject(object)
        }
    }
}

With the Array Extension you can simplify your last 4 lines of code into a single line of code to remove an array of objects.

// Swift 2
var wordArray = ["Apple", "Carrot", "Peanut Butter"]
wordArray.append("Hummus")
wordArray.insert("Greek Salad", atIndex: 0)

// Find the objects to remove
var wordsToDelete: [String] = [String]()
for word in wordArray {
    if word.lowercaseString.characters.contains("p") {
        wordsToDelete.append(word)
    }
}

// Remove an array of objects
wordArray.removeObjectsInArray(wordsToDelete)

Free Online Swift App Course

Subscribe and get access to the Free iPhone App Course – you can make your first iPhone app using Swift.