45

I'd like to set a maximum number of characters allowed to be typed both in a UITextView and a UITextField. This number will be then shown in a little label (for user's reference, Twitter Style.)

Fattie
  • 27,874
  • 70
  • 431
  • 719
biggreentree
  • 1,633
  • 3
  • 20
  • 35
  • You are checking the current length of the text, not what the length is about to become. – rmaddy Oct 04 '15 at 16:12
  • http://stackoverflow.com/a/1773257/4475605 – Adrian Oct 04 '15 at 16:35
  • went on the link I added that code in ViewDidLoad and replaced `UITextField` with `myMessageObjectLabel ` is it right? Now I got this error Use of undeclared type 'myMessageObjectLabel'. I'm using swift 1.2 at now, could be a problem? – biggreentree Oct 05 '15 at 08:29

10 Answers10

120

Update Swift 4.X

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
    let numberOfChars = newText.count
    return numberOfChars < 10    // 10 Limit Value
}

Try this out:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
    let numberOfChars = newText.characters.count // for Swift use count(newText)
    return numberOfChars < 10;
}
Rizwan
  • 3,324
  • 3
  • 17
  • 38
Abhinav
  • 37,684
  • 43
  • 191
  • 309
  • This is correct but why is the variable named `numberOfLines` when it is the number of characters? – rmaddy Oct 04 '15 at 16:20
  • yes this is correct, i forgot about the number of lines – William Kinaan Oct 04 '15 at 16:21
  • @WilliamKinaan What number of lines? There's nothing in the question about limiting the number of lines. – rmaddy Oct 04 '15 at 16:24
  • Thanks @rmaddy for pointing out. It was a typo in a rush :-), corrected it now! – Abhinav Oct 04 '15 at 16:25
  • I added this code in `ViewDidLoad` and replaced `textView: UITextView` with `myMessageTextView ` is it right? Now I got this error String does not have a member named 'characters'. I'm using swift 1.2 at now, could be a problem? – biggreentree Oct 05 '15 at 08:24
  • Yes, as I mentioned in my code. For Swift use `count(newText)`. I am using Swift 2. – Abhinav Oct 05 '15 at 08:25
  • Hey ... 1 minute, you said you added my code in `viewDidLoad`? Well thats not correct. In your `viewDidLoad` you would add your view controller as delegate to your `UITextField` something like this `myMessageObjectLabel.delegate = self`. The code that I have shared above is a delegate call back from `UITextField` - add in your class file as an independent function and it should get called back for each character typed in by user in your text field. – Abhinav Oct 05 '15 at 08:42
  • You need to conform to `UITextViewDelegate` protocol. I guess by mistake you added text filed delegate. Please check that out. @biggreentree – Abhinav Oct 06 '15 at 11:21
  • I am sure its very simple stuff. Would it be possible for you to share the project on github? I can take a look. @biggreentree – Abhinav Oct 06 '15 at 12:24
  • Hey, your method signature is totally off. Take a look at my post. You should not use `self.startingMessageTextView `, instead it should be `UITextView`. Use my method word by word. @biggreentree – Abhinav Oct 06 '15 at 12:27
  • you are totally right, I changed it because in my mind I was acting only on that selected `UITextView` everything works great! thanks I'll do the same on my `UITextField` for object – biggreentree Oct 06 '15 at 12:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91487/discussion-between-abhinav-and-biggreentree). – Abhinav Oct 06 '15 at 12:31
  • 2
    Shouldn't the last line be `return numberOfChars <= 10;` (the less-than symbol should be less-than-or-equal-to)? – Roberto Sep 13 '16 at 11:40
  • @Abhinav how to restrict the copied text in here? like, clipboard got 2000 characters string where textview allows 1500 character, so when i paste the long string it let the textview empty instead of copying 1500 characters. – Steve Jan 19 '18 at 10:07
  • 3
    If you want to allow the user to delete chars when they "are over the limit" (can happen if you lower the char limit and user is editing with old (longer text), add a guard...`guard !text.isEmpty else { return true }` – Swany Apr 08 '20 at 16:56
38

SWIFT 4

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
     let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
     return newText.count < 10
}
Yaroslav Dukal
  • 3,894
  • 29
  • 36
12

Swift 4:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
  let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
  return newText.count <= 70
}
budiDino
  • 13,044
  • 8
  • 95
  • 91
Bogdan Bystritskiy
  • 1,325
  • 12
  • 10
9

Try this out:-

 func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    print("chars \(textView.text.characters.count) \( text)")

    if(textView.text.characters.count > 20 && range.length == 0) {
        print("Please summarize in 20 characters or less")
        return false;
    }

    return true;
}
Abhijeet Mallick
  • 1,740
  • 2
  • 16
  • 21
8

Swift 3.0

Just override this UITextFieldDelegate function, set the desired characterLimit variable and you are good to go:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
{        
        let characterLimit = 5
        let newText = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
        let numberOfChars = newText.characters.count
        return numberOfChars < characterLimit
}
Junaid Mukhtar
  • 815
  • 9
  • 16
4

Update for Swift 5

Gives the most forward result

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    return range.location < 140 // limit to 140 chars
}
3

Swift 4 , Xcode 9.1 GM

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    return textView.text.count + (text.count - range.length) <= 200
}
Krunal Patel
  • 1,649
  • 1
  • 14
  • 22
3

Swift 4/ Xcode 9.1

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    let currentText = textView.text ?? ""
    guard let stringRange = Range(range, in: currentText) else { return false }
    let changedText = currentText.replacingCharacters(in: stringRange, with: text)
    return changedText.count <= 399 // Pass your character count here 
}
Arpit Jain
  • 1,660
  • 12
  • 23
2

Swift 5

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    var newText = textView.text!
    newText.removeAll { (character) -> Bool in
        return character == " " || character == "\n"
    }

    return (newText.count + text.count) <= 40
}
Gerasim
  • 21
  • 2
1

Adding support of pasting text with cutting it by a maxLength + avoiding UNDO action crash:

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if let maxLength = maxLength {
        let maxReplacementLength = min(range.length, maxLength - range.location)
        let replacementRange = NSRange(location: range.location, length: maxReplacementLength)
        let result = NSString(string: (textView.text ?? "")).replacingCharacters(in: replacementRange, with: text)
        
        if result.count <= maxLength && range.length <= maxLength - range.location  {
            return true
        }
        textView.text = String(result[..<result.index(result.startIndex, offsetBy: min(result.count, maxLength))])
        
        return false
    }
    
    return true
}
Hopreeeenjust
  • 257
  • 4
  • 5