Set the maximum character length of a UITextField in Swift

154,649

Solution 1

  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

Solution 2

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!

Solution 3

In Swift 4, simply use:

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    return range.location < 10
}

Solution 4

The same way Steven Schmatz did it but using Swift 3.0 :

//max Length
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool
{
    let maxLength = 4
    let currentString: NSString = textField.text! as NSString
    let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
    return newString.length <= maxLength
}

Solution 5

For Swift 5:

Just write one line to set the maximum character length:

 self.textField.maxLength = 10

For more details, see Max character limit of UITextField and allowed characters Swift. (Also credited.)

Share:
154,649

Related videos on Youtube

ishkur88
Author by

ishkur88

Swift Developer

Updated on November 12, 2021

Comments

  • ishkur88
    ishkur88 over 2 years

    I know there are other topics on this, but I can't seem to find out how to implement it.

    I'm trying to limit a UITextField to only five characters.

    Preferably alphanumeric, -, ., and _.

    I've seen this code:

    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
    }
    

    and

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    
        let length = count(textField.text.utf16) + count(string.utf16) - range.length
        return length <= 10
    }
    

    How can I actually implement it? Which "textfield" should I swap out for my custom named UITextField?

    • Leo Dabus
      Leo Dabus over 5 years
      Swift 4 implementation stackoverflow.com/a/46513151/2303865
    • Fattie
      Fattie almost 5 years
      Quick alert - to shorten a String in Swift these days you can finally just .prefix(n)
  • ishkur88
    ishkur88 almost 9 years
    Thank you so much for the prompt reply! If I set this one textfield as the delegate would I be able to modify other textfields?
  • Alaeddine
    Alaeddine almost 9 years
    yes, and you will get the textfield in question (being edited ) as the first parameter textField in the method func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
  • ishkur88
    ishkur88 almost 9 years
    But where would I put in the second parameter? I don't reference myTextField again after I set it as a delegate.
  • ishkur88
    ishkur88 almost 9 years
    Like if I wanted to make another textfield 0-9 only for phone numbers.
  • Alaeddine
    Alaeddine almost 9 years
    every time a textfield is being edited, the callback shouldChangeCharactersInRange is called, this is for all textfields, you receive the callback in the same place shouldChangeCharactersInRange and inside this method you can know which textfield is being edited thanks to the passed parameter textField you can for example give a tag for each textfield and test inside the shouldChangeCharactersInRange and for each textfield perform the validation of the content
  • Alaeddine
    Alaeddine almost 9 years
    @ishkur88 I have updated the answer with another example note the if mytextField == numberField { to check the textField that is being edited
  • Theo Bendixson
    Theo Bendixson over 7 years
    Does this particular solution allow the user to enter a backspace character once the user has hit the character limit? Would we need a way to let backspaces through?
  • J. Doe
    J. Doe about 7 years
    Seems legit! Thank you.
  • mylovemhz
    mylovemhz almost 7 years
    That all this has to be done to achieve something so common and so simple blows my mind. They couldn't just give us a simple textField.maxLength built-in...anyway your solution is great, thanks!
  • jonathan3087
    jonathan3087 over 6 years
    Wow, best tip I have ever had on SO. I'd up vote it 100 if I could!
  • Alan Scarpa
    Alan Scarpa over 6 years
    For Swift 4, this self.characters is deprecated. It is now just let c = self
  • Vamshi Krishna
    Vamshi Krishna over 6 years
    Cannot we do something like this for regex validation (like phoneNumber, emailId, userName)?
  • Angel G. Olloqui
    Angel G. Olloqui about 6 years
    The solution is handy but the map of textfields at the top will actually produce a retain cycle.
  • Fattie
    Fattie about 6 years
    hi @AngelGarcíaOlloqui - it's an excellent point, in the unusual case where they're not just from storyboards, you'd have to attend to that. Good thinking!
  • Keyhan Kamangar
    Keyhan Kamangar over 5 years
    Thanks for your answer, Can u explain maxLengths please?
  • Ankur Lahiry
    Ankur Lahiry over 5 years
    The answer I am looking for :D
  • user832
    user832 over 5 years
    this should be the selected answer. Simple and workes well.
  • Slavcho
    Slavcho over 5 years
    It doesnt work. What if you tap in the middle of the string and you can type more than X chars.
  • Leo Dabus
    Leo Dabus over 5 years
    super.didMoveToSuperview() "The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes." Considering it calling super for that method is pointless
  • Fattie
    Fattie over 5 years
    an excellent point @LeoDabus , thanks! I'll leave it there to help new programmers with the typical pattern; Happy new year!
  • Leo Dabus
    Leo Dabus over 5 years
    @Fattie you are welcome. Happy new year for you too.
  • Fattie
    Fattie over 5 years
    @TheoBendixson , the more modern solution of simply using . editingChanged completely handles all such issues.
  • cornr
    cornr over 5 years
    This does not handle copy and paste
  • Saqib Saud
    Saqib Saud over 5 years
    instead of range.location < 10, you can use textField.text.length < 10. This solution is simple and elegant.
  • 10623169
    10623169 about 5 years
    This should be the accepted answer. Works perfectly, with no bugs.
  • zeeshan
    zeeshan almost 5 years
    This is the solution, simple and elegant, with no boilerplate code.
  • ViruMax
    ViruMax almost 5 years
    This solution creates a new issue while typing in other languages like Mandarin, Korean, etc.
  • Hasya
    Hasya almost 5 years
    Good answer. Appreciated.
  • juancazalla
    juancazalla almost 5 years
    WARNING FOR THOSE USING THIS SOLUTION! This solution has some problems. One of them is that if the user types at the beginning of the textField, you are going to allow them to type the new character and the last one will be removed, also, the cursor will jump to the last character in the field. Another problem is that if you set the text programmatically, it will allow you to set a text bigger than the limit. Another problem occurs if you undo a change (CMD+Z with an external keyboard) it will crash if you tried to add a digit over the limit previously.
  • Fattie
    Fattie almost 5 years
    hi @juancazalla ! the first three are desired behaviors, and depend on what you or the client wants. regarding the external keyboard undo issue, that's a great point, I did not think of testing with an external keyboard! I will try to repo that!
  • Sachin Rana
    Sachin Rana over 4 years
    Suppose I have 2 textfields. Both require different max char limit, one require 10 char and other require 20 char. In that case what approach should I need to follow. Is there any way to make maxLength variable dynamic?
  • Сергей Билык
    Сергей Билык over 4 years
    You can use this solution: if textField.text?.count >= 12 { return false }
  • Reza Dehnavi
    Reza Dehnavi about 4 years
    it doesn't work when past a text if you want to work in past action you should add string.count < MAX_LENGTH
  • iDev
    iDev about 4 years
    This cannot work. Location is not the length of the string but the position of the cursor / selelction.
  • Dylan
    Dylan almost 4 years
    it gives me an error saying Expression type '()' is ambiguous without more context on prefix
  • Dylan
    Dylan almost 4 years
    hi @Fattie I posted my question here stackoverflow.com/q/62165247/6800631
  • Leo Dabus
    Leo Dabus almost 4 years
    @Fattie you need to update the post textField.text = String(textField.text!.prefix(maxLength)) and text = String(text!.prefix(4))
  • Leo Dabus
    Leo Dabus almost 4 years
    Prefix returns a substring
  • Leo Dabus
    Leo Dabus almost 4 years
    I think since String started conforming to RangeReplaceableCollection
  • Leo Dabus
    Leo Dabus almost 4 years
    @Fattie You can safely force unwrap it. Its default value is an empty String. It will NEVER return nil. You can even set it to nil and it wont return nil after that.
  • Fattie
    Fattie almost 4 years
    hi @LeoDabus , you know, I wonder if that assumption in the specific UITextField class would confuse newer users; it's not something one can assume generally ... :O
  • Leo Dabus
    Leo Dabus almost 4 years
    You can warn them about this case being an exception :) As well as the reason why there is no need to call super.didMoveToSuperview()
  • Leo Dabus
    Leo Dabus almost 4 years
    The text property being optional allows you to assign an optional string to it without the need to unwrap its value
  • FontFamily
    FontFamily over 3 years
    While this solution may seem straightforward, there is actually a lot more code that is required to implement this. This answer isn't very helpful by itself and the addition of an explanation and inclusion of other relevant pieces of code might be helpful.
  • Silvering
    Silvering about 3 years
    Best answer. Thanks
  • deepOcean
    deepOcean over 2 years
    Worked in my case, only digits in textfield
  • Peter Mortensen
    Peter Mortensen over 2 years
    Isn't something missing from the source code near "class MyViewController"? The syntax highlighting is off.
  • Peter Mortensen
    Peter Mortensen over 2 years
    There is no one here by the name "Steven Schmatz". What answer does it refer to? Is it SwiftMatt's answer? The other three possibilities are "Alaeddine", "ZaEeM ZaFaR", and "Cloy" (deleted answer - link-only answer).
  • Peter Mortensen
    Peter Mortensen over 2 years
    There is no one here by the name "Frouo". What answer does it refer to?
  • Peter Mortensen
    Peter Mortensen over 2 years
    Will that work? MAX_LENGHT looks like a misspelling. Why isn't it MAX_LENGTH? Where is it defined? Dictionary: length
  • Peter Mortensen
    Peter Mortensen over 2 years
    What is meant by the last sentence? Can you elaborate? What is not checked? What is only checked? For example, do you mean "Here I only checked for characters allowed in textField"? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).
  • TD540
    TD540 over 2 years
    Defined nowhere :) I think his intention is for the reader of his comment to replace it with the wanted maximum length. Besides that, this answer should be the solution.