Set the maximum character length of a UITextField in Swift

Modern Swift

Note that much of the example code online regarding this problem is extremely out of date.

Paste the following into any Swift file in your project. (You can name the file anything, for example, "Handy.swift".)

This finally fixes one of the stupidest problems in iOS:

enter image description here

Your text fields now have a .maxLength.

It is completely OK to set that value in storyboard during development, or, set it in code while the app is running.

// simply have this in any Swift file, say, Handy.swift

import UIKit
private var __maxLengths = [UITextField: Int]()
extension UITextField {
    @IBInspectable var maxLength: Int {
        get {
            guard let l = __maxLengths[self] else {
               return 150 // (global default-limit. or just, Int.max)
            }
            return l
        }
        set {
            __maxLengths[self] = newValue
            addTarget(self, action: #selector(fix), for: .editingChanged)
        }
    }
    func fix(textField: UITextField) {
        let t = textField.text
        textField.text = t?.prefix(maxLength).string
    }
}

It's that simple.


Footnote - these days to safely truncate a String in swift, you simply .prefix(n)


An even simpler one-off version...

The above fixes all text fields in your project.

If you just want one particular text field to simply be limited to say "4", and that's that...

class PinCodeEntry: UITextField {
    
    override func didMoveToSuperview() {
        
        super.didMoveToSuperview()
        addTarget(self, action: #selector(fixMe), for: .editingChanged)
    }
    
    @objc private func fixMe() { text = text?.prefix(4) }
}

Phew! That's all there is to it.

(Just BTW, here's a similar very useful tip relating to UITextView, https://stackoverflow.com/a/42333832/294884 )


For the OCD programmer (like me)...

As @LeoDabus reminds, .prefix returns a substring. If you're incredibly caring, this

let t = textField.text
textField.text = t?.prefix(maxLength)

would be

if let t: String = textField.text {
    textField.text = String(t.prefix(maxLength))
}

Enjoy!


  1. Your view controller should conform to UITextFieldDelegate, like below:

    class MyViewController: UIViewController, UITextFieldDelegate {
    
    }
    
  2. Set the delegate of your textfield: myTextField.delegate = self

  3. Implement the method in your view controller:

    textField(_:shouldChangeCharactersInRange:replacementString:)
    

All together:

class MyViewController: UIViewController, UITextFieldDelegate  // Set delegate to class

@IBOutlet var mytextField: UITextField             //  textfield variable

override func viewDidLoad() {
    super.viewDidLoad()
    mytextField.delegate = self                  // set delegate
}


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
                       replacementString string: String) -> Bool
{
    let maxLength = 4
    let currentString: NSString = textField.text
    let newString: NSString =  currentString.stringByReplacingCharactersInRange(range, withString: string)

    return newString.length <= maxLength
}

For Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let maxLength = 1
    let currentString: NSString = (textField.text ?? "") as NSString
    let newString: NSString =  currentString.replacingCharacters(in: range, with: string) as NSString

    return newString.length <= maxLength
}

For Swift 5

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let maxLength = 1
    let currentString = (textField.text ?? "") as NSString
    let newString = currentString.replacingCharacters(in: range, with: string)

    return newString.count <= maxLength
}

Allowing only a specified set of characters to be entered into a given text field

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    var result = true

    if mytextField == numberField {
        if count(string) > 0 {
            let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789.-").invertedSet
            let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
            result = replacementStringIsLegal
        }
    }

    return result
}

How to program an iOS text field that takes only numeric input with a maximum length