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 Create a Random Int Number in Swift 2 - Swift Tips 7

Good random numbers in iPhone apps are really important (the same is true for the lottery!). A good random number is from a range [start, end] that gives every value an equal probability of occurring.

An equal probability means that if you were to flip a coin—you should always get close to 50% heads and 50% tails over 100 coin tosses.

Download the sample Xcode project that shows how to create random Int numbers in Swift with a working iPhone app.

Swift Random Int Range

In Swift you should use the arc4random_uniform(N) function because it creates better random numbers (i.e.: equal probability).

arc4random_uniform(N) creates a number within from [0, N - 1], which means if you want numbers in the range [0, 100] you need to call arc4random_uniform(N + 1).

  1. Random Int [A, B] where A < B

    let A: UInt32 = 10 // UInt32 = 32-bit positive integers (unsigned)
     let B: UInt32 = 20
     let number = arc4random_uniform(B - A + 1) + A
  2. Random Int [0, 100]

    // Using the equation (100 - 0 + 1) + 0 becomes (101)
     let number = arc4random_uniform(101) // [0, 100]
  3. Random Int [1, 100]

    // Using the equation (100 - 1 + 1) + 1 becomes (100) + 1
     let number2 = arc4random_uniform(100) + 1 // [1, 100]
  4. Random Int [50, 100]

    // Using the equation (100 - 50 + 1) + 50 becomes (51) + 50
     let number3 = arc4random_uniform(51) + 50 // [50, 100]
  5. Unsafe: Swift method for a random Int within [A, B] where A < B

    Swift is strongly-typed which means that you need to explicitly change numbers that are Int into UInt32 and vice versa for the code to compile. Use the Int() and UInt32() initializers to convert between the types.

    func unsafeRandomIntFrom(start: Int, to end: Int) -> Int {
         return Int(arc4random_uniform(UInt32(end - start + 1))) + start
     }
    
     unsafeRandomIntFrom(50, to: 100)  // positive ascending ranges work
     unsafeRandomIntFrom(-50, to: 100) // negative ranges work!
     //unsafeRandomIntFrom(500, to: 100) // Crash! EXC_BAD_INSTRUCTION

    Crash: Technically this will crash if A > B with a EXC_BAD_INSTRUCTION because the parameter of arc4random_uniform() is UInt32 and can only hold positive 32-bit integer values.

  6. Safe Swift method for a random Int within [A, B]

    func randomIntFrom(start: Int, to end: Int) -> Int {
         var a = start
         var b = end
         // swap to prevent negative integer crashes
         if a > b {
             swap(&a, &b)
         }
         return Int(arc4random_uniform(UInt32(b - a + 1))) + a
     }

Int Type Extension

You can make the randomIntFrom(_:end:) a static function on the type Int using a static function. This code block is then reusable in any of your projects to make random number generation simple.

extension Int {
    func randomIntFrom(start: Int, to end: Int) -> Int {
        var a = start
        var b = end
        // swap to prevent negative integer crashes
        if a > b {
            swap(&a, &b)
        }
        return Int(arc4random_uniform(UInt32(b - a + 1))) + a
    }
}

Where Does arc4random_uniform() Come From?

This random function is actually written in the C programming language (which you can use in Swift!). Read the arc4random man page (i.e.: manual page) for all the details.

Download the Code

Download the sample Xcode project that shows you how to create random Int numbers in Swift with a working iPhone app.

You can play change the range of numbers with the iPhone app to see how to use the arc4random_uniform() function correctly in your own apps.