ChatGPT解决这个技术问题 Extra ChatGPT

Set the maximum character length of a UITextField

How can I set the maximum amount of characters in a UITextField on the iPhone SDK when I load up a UIView?

this incredibly old answer is very out of date - the answer is now trivial: stackoverflow.com/a/38306929/294884

C
Community

While the UITextField class has no max length property, it's relatively simple to get this functionality by setting the text field's delegate and implementing the following delegate method:

Objective-C

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // Prevent crashing undo bug – see note below.
    if(range.length + range.location > textField.text.length)
    {
        return NO;
    }
        
    NSUInteger newLength = [textField.text length] + [string length] - range.length;
    return newLength <= 25;
}

Swift

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
    let currentCharacterCount = textField.text?.count ?? 0
    if range.length + range.location > currentCharacterCount {
        return false
    }
    let newLength = currentCharacterCount + string.count - range.length
    return newLength <= 25
}

Before the text field changes, the UITextField asks the delegate if the specified text should be changed. The text field has not changed at this point, so we grab it's current length and the string length we're inserting (either through pasting copied text or typing a single character using the keyboard), minus the range length. If this value is too long (more than 25 characters in this example), return NO to prohibit the change.

When typing in a single character at the end of a text field, the range.location will be the current field's length, and range.length will be 0 because we're not replacing/deleting anything. Inserting into the middle of a text field just means a different range.location, and pasting multiple characters just means string has more than one character in it.

Deleting single characters or cutting multiple characters is specified by a range with a non-zero length, and an empty string. Replacement is just a range deletion with a non-empty string.

A note on the crashing "undo" bug

As is mentioned in the comments, there is a bug with UITextField that can lead to a crash.

If you paste in to the field, but the paste is prevented by your validation implementation, the paste operation is still recorded in the application's undo buffer. If you then fire an undo (by shaking the device and confirming an Undo), the UITextField will attempt to replace the string it thinks it pasted in to itself with an empty string. This will crash because it never actually pasted the string in to itself. It will try to replace a part of the string that doesn't exist.

Fortunately you can protect the UITextField from killing itself like this. You just need to ensure that the range it proposes to replace does exist within its current string. This is what the initial sanity check above does.

swift 3.0 with copy and paste working fine.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

Hope it's helpful to you.


Found a solution by surrounding those 2 lines with if (textField == _ssn) { } and adding return YES; at the end of the method, which will allow all other UITextFields to accept text without any restriction. Nifty!
Good answer, but the ternary operator is superfluous; you could just put return newLength <= 25;
What if you just want the text to not spill over the frame of the textfield; not all characters are the same width, right ?
@bherry In Swift, the check for the undo case seems to break the entry of emoji. Shouldn't the count(textField.text) actually be count(textField.text.utf16) to match the objc/uikit reporting in range (vs Swift's variant of count on strings)?
For the Swift code comparing the textField.text?.characters.count with the range will add a bug when using Emoji characters. You should use the textField.text?.utf16.count for it to function as described.
C
Community

Swift 4

import UIKit

private var kAssociationKeyMaxLength: Int = 0

extension UITextField {
    
    @IBInspectable var maxLength: Int {
        get {
            if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                return length
            } else {
                return Int.max
            }
        }
        set {
            objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
            addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }
    
    @objc func checkMaxLength(textField: UITextField) {
        guard let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }
        
        let selection = selectedTextRange
        
        let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        let substring = prospectiveText[..<indexEndOfText]
        text = String(substring)
        
        selectedTextRange = selection
    }
}

Edit: memory leak issue fixed.

https://i.stack.imgur.com/t8WVj.png


Great idea Frouo! I expanded upon it in my answer to move the maxLength trimming to a String extension so that it can also be used for things like UITextView instances, and to add a convenience function to take advantage of these String extensions in a UITextField extension.
Doesn't this global variable create memory leaks, by holding references to all the textviews (which reference the superviews up until root-)
@Ixx I have edited to fix the memory leak issue you pointed out + swift 3. Thanks
the most beautiful way to achive it ! Thanks
can anyone provide me its objective version
C
Community

Thank you august! (Post)

This is the code that I ended up with which works:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField.text.length >= MAX_LENGTH && range.length == 0)
    {
        return NO; // return NO to not change text
    }
    else
    {return YES;}
}

Unfortunately, this solution fails to stop users copy-and-pasting into a text field, therefore allowing them to bypass the limit. Sickpea's answer copes with this situation correctly.
What is with people having an if statement to return NO or YES? Try this: return !(textField.text.length >= MAX_LENGTH && range.length == 0);
or this return textField.text.length < MAX_LENGTH || range.length != 0;
J
Jmini

To complete August answer, an possible implementation of the proposed function (see UITextField's delegate).

I did not test domness code, but mine do not get stuck if the user reached the limit, and it is compatible with a new string that comes replace a smaller or equal one.

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //limit the size :
    int limit = 20;
    return !([textField.text length]>limit && [string length] > range.length);
}

e
etolstoy

You can't do this directly - UITextField has no maxLength attribute, but you can set the UITextField's delegate, then use:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

I agree, this is the best way forward, but it stays a bit of a hack. Submit a bug report to Apple that you'd like to see a property for text length. I'm definitely interested in this as well.
@avocade, it's not a hack: it's an example where you have to do basic framework code that Apple should've done for you. There are MANY many examples of this in the iOS SDK.
V
Vincent

Often you have multiple input fields with a different length.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    int allowedLength;
    switch(textField.tag) {
        case 1: 
            allowedLength = MAXLENGTHNAME;      // triggered for input fields with tag = 1
            break;
        case 2:
            allowedLength = MAXLENGTHADDRESS;   // triggered for input fields with tag = 2
            break;
        default:
            allowedLength = MAXLENGTHDEFAULT;   // length default when no tag (=0) value =255
            break;
    }

    if (textField.text.length >= allowedLength && range.length == 0) {
        return NO; // Change not allowed
    } else {
        return YES; // Change allowed
    }
}

P
Paulo Moura

The best way would be to set up a notification on the text changing. In your -awakeFromNib of your view controller method you'll want:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];

Then in the same class add:

- (void)limitTextField:(NSNotification *)note {
    int limit = 20;
    if ([[myTextField stringValue] length] > limit) {
        [myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
    }
}

Then link up the outlet myTextField to your UITextField and it will not let you add any more characters after you hit the limit. Be sure to add this to your dealloc method:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];

Although I did this to remove errors > myTextField.text=[myTextField.text substringToIndex:limit];
J
Jonathan Gurebo

I created this UITextFieldLimit subclass:

Multiple textfields supported

Set the text length limit

Paste prevention

Displays a label of left characters inside the textfield, get hidden when you stop editing.

Shake animation when no characters left.

Grab the UITextFieldLimit.h and UITextFieldLimit.m from this GitHub repository:

https://github.com/JonathanGurebo/UITextFieldLimit

and begin to test!

Mark your storyboard-created UITextField and link it to my subclass using the Identity Inspector:

https://i.stack.imgur.com/7lbJp.png

Then you can link it to an IBOutlet and set the limit(default is 10).

Your ViewController.h file should contain: (if you wan't to modify the setting, like the limit)

#import "UITextFieldLimit.h"

/.../

@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet

Your ViewController.m file should @synthesize textFieldLimit.

Set the text length limit in your ViewController.m file:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

    [textFieldLimit setLimit:25];// <-- and you won't be able to put more than 25 characters in the TextField.
}

Hope the class helps you. Good luck!


For the small need of the character limit, I think adding your class would just be overkill.
B
Bhavin Bhadani

This should be enough to solve the problem (replace 4 by the limit u want). Just make sure to add delegate in IB.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
     NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
     return (newString.length<=4);
}

H
Hitesh Surani

Use below extension to set the maximum character length of a UITextField and UITextView.

Swift 4.0

    private var kAssociationKeyMaxLength: Int = 0
    private var kAssociationKeyMaxLengthTextView: Int = 0
    extension UITextField {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
                addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
            }
        }

        @objc func checkMaxLength(textField: UITextField) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

UITextView

extension UITextView:UITextViewDelegate {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLengthTextView) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                self.delegate = self

                objc_setAssociatedObject(self, &kAssociationKeyMaxLengthTextView, newValue, .OBJC_ASSOCIATION_RETAIN)
            }
        }

        public func textViewDidChange(_ textView: UITextView) {
            checkMaxLength(textField: self)
        }
        @objc func checkMaxLength(textField: UITextView) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

You can set limit below.

https://i.stack.imgur.com/CaZPP.png


best answer by far ,,, thanks a lot great solution when there is many textfields that need different lengths
Really great solution for textfield and textview control character input limit. Its save code lines and time too for developer ...:)
This works better than the other solutions I found. For instance, if you have emojis in your textfield, other extensions I found would skip to the end of the line when editing. But your code doesn't do that. Thanks!
s
samvermette

I simulate the actual string replacement that's about to happen to calculate that future string's length:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if([newString length] > maxLength)
       return NO;

    return YES;
}

H
Hiren

https://i.stack.imgur.com/NcsM3.png

import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            guard let length = maxLengths[self]
            else {
                return Int.max
            }
            return length
        }
        set {
            maxLengths[self] = newValue
            addTarget(
                self,
                action: Selector("limitLength:"),
                forControlEvents: UIControlEvents.EditingChanged
            )
        }
    }

    func limitLength(textField: UITextField) {
        guard let prospectiveText = textField.text
            where prospectiveText.characters.count > maxLength else {
                return
        }
        let selection = selectedTextRange
        text = prospectiveText.substringWithRange(
            Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
        )
        selectedTextRange = selection
    }

}

Clean and perfect solution
Holding a UITextField in a global field will retain them in the memory even after the UIViewController is dismissed. This is a memory leak. Don't use this method.
G
Gilad Brunfman

Swift 3 version //***** This will NOT work with Swift 2.x! *****//

First create a new Swift file : TextFieldMaxLength.swift, and then add the code below:

import UIKit

private var maxLengths = [UITextField: Int]()

extension UITextField {

   @IBInspectable var maxLength: Int {

      get {

          guard let length = maxLengths[self] 
             else {
                return Int.max
      }
      return length
   }
   set {
      maxLengths[self] = newValue
      addTarget(
         self,
         action: #selector(limitLength),
         for: UIControlEvents.editingChanged
      )
   }
}
func limitLength(textField: UITextField) {
    guard let prospectiveText = textField.text,
        prospectiveText.characters.count > maxLength
    else {
        return
    }

   let selection = selectedTextRange
   let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
   text = prospectiveText.substring(to: maxCharIndex)
   selectedTextRange = selection
   }
}

and then you will see in Storyboard a new field (Max Length) when you select any TextField

if you still have more questions check out this link: http://www.globalnerdy.com/2016/05/18/ios-programming-trick-how-to-use-xcode-to-set-a-text-fields-maximum-length-visual-studio-style/


Warning, this global variable create memory leaks, by holding references to all the textviews.
V
Vishal Kumar

Using Interface builder you can link and get the event for "Editing changed" in any of your function. Now there you can put check for the length

- (IBAction)onValueChange:(id)sender 
{
    NSString *text = nil;
    int MAX_LENGTH = 20;
    switch ([sender tag] ) 
    {
        case 1: 
        {
            text = myEditField.text;
            if (MAX_LENGTH < [text length]) {
                myEditField.text = [text substringToIndex:MAX_LENGTH];
            }
        }
            break;
        default:
            break;
    }

}

w
wroluk

The following code is similar to sickp's answer but handles correctly copy-paste operations. If you try to paste a text that is longer than the limit, the following code will truncate the text to fit the limit instead of refusing the paste operation completely.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    static const NSUInteger limit = 70; // we limit to 70 characters
    NSUInteger allowedLength = limit - [textField.text length] + range.length;
    if (string.length > allowedLength) {
        if (string.length > 1) {
            // get at least the part of the new string that fits
            NSString *limitedString = [string substringToIndex:allowedLength];
            NSMutableString *newString = [textField.text mutableCopy];
            [newString replaceCharactersInRange:range withString:limitedString];
            textField.text = newString;
        }
        return NO;
    } else {
        return YES;
    }
}

P
Påhl Melin

To make it work with cut & paste of strings of any length, I would suggest changing the function to something like:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        NSInteger insertDelta = string.length - range.length;

        if (textField.text.length + insertDelta > MAX_LENGTH)
        {
           return NO; // the new string would be longer than MAX_LENGTH
        }
        else {
            return YES;
        }
    }

S
Shan Ye

Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }
    let newLength = text.count + string.count - range.length
    return newLength <= 10
}

Why the guard?
check if the text is nil, if you want, you can also use if @oddRaven
o
onCompletion

Swift 2.0 +

First of all create a class for this process. Lets call it StringValidator.swift.

Then just paste the following code inside it.

import Foundation

extension String {

func containsCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) != nil
}

func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}


func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) == nil
}

func isNumeric() -> Bool
{
let scanner = NSScanner(string: self)
scanner.locale = NSLocale.currentLocale()

return scanner.scanDecimal(nil) && scanner.atEnd
}

}

Now save the class.....

Usage..

Now goto your viewController.swift class and make your textfield's outlets as..

@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField!   //Second textfield

Now goto the textfield's shouldChangeCharactersInRange method and use like the following.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if string.characters.count == 0 {
        return true
    }
    let latestText = textField.text ?? ""
    let checkAbleText = (latestText as NSString).stringByReplacingCharactersInRange(range, withString: string)


    switch textField {

    case contactEntryTxtFld:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    case contactEntryTxtFld2:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    default:
        return true
    }

}

Don't forget to set the delegate protocol/methods of textfields.

Let me explain about this... I am using the simple extension process of string which I wrote inside an another class. Now I am just calling those extension methods from another class where I need them by adding check and maximum value.

Features...

It will set maximum limit of a particular textfield. It will set type of accepted keys for particular textfield.

Types...

containsOnlyCharactersIn //Accepts only Characters.

containsCharactersIn //Accepts combination of characters

doesNotContainsCharactersIn //Will not accept characters

Hope this helped.... Thanks..


C
Community

swift 3.0

This code is working fine when you are paste string more than your character limits.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

Thanks for your votes. :)


UITextField, not UITextView.
V
Victor Choy

I give a supplementary answer based on @Frouo. I think his answer is the most beautiful way. Becuase it's a common control we can reuse.

private var kAssociationKeyMaxLength: Int = 0

extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                return length
            } else {
                return Int.max
            }
        }
        set {
            objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
            self.addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }

    func checkMaxLength(textField: UITextField) {

        guard !self.isInputMethod(), let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }

        let selection = selectedTextRange
        let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        text = prospectiveText.substring(to: maxCharIndex)
        selectedTextRange = selection
    }

    //The method is used to cancel the check when use Chinese Pinyin input method.
    //Becuase the alphabet also appears in the textfield when inputting, we should cancel the check.
    func isInputMethod() -> Bool {
        if let positionRange = self.markedTextRange {
            if let _ = self.position(from: positionRange.start, offset: 0) {
                return true
            }
        }
        return false
    }

}

a
anders

This is the correct way to handle max length on UITextField, it allows the return key to exit the resign the textfield as first responder and lets the user backspace when they reach the limit

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int MAX_LENGHT = 5;
    if([string isEqualToString:@"\n"])
    {
        [textField resignFirstResponder];
        return FALSE;
    }
    else if(textField.text.length > MAX_LENGHT-1)
    {
        if([string isEqualToString:@""] && range.length == 1)
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
    {
        return TRUE;
    }
}

J
Joaquin Pereira

What about this simple approach. Its working fine for me.

extension UITextField {

    func  charactersLimit(to:Int) {

        if (self.text!.count > to) {
            self.deleteBackward()
        }
    }
}

Then:

someTextField.charactersLimit(to:16)

8
8suhas

Other answers do not handle the case where user can paste a long string from clipboard. If I paste a long string it should just be truncated but shown. Use this in your delegate:

static const NSUInteger maxNoOfCharacters = 5;

-(IBAction)textdidChange:(UITextField * )textField
{
NSString * text = textField.text;

if(text.length > maxNoOfCharacters)
{
    text = [text substringWithRange:NSMakeRange(0, maxNoOfCharacters)];
    textField.text = text;
}

// use 'text'

}

A
Albert Renshaw

Got it down to 1 line of code :)

Set your text view's delegate to "self" then add the <UITextViewDelegate> in your .h and the following code in your .m .... you can adjust the number "7" to be whatever you want your MAXIMUM number of characters to be.

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return ((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length)>0);
}

This code accounts for typing new characters, deleting characters, selecting characters then typing or deleting, selecting characters and cutting, pasting in general, and selecting characters and pasting.

Done!

Alternatively, another cool way to write this code with bit-operations would be

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return 0^((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length));
}

S
Stunner

I have open sourced a UITextField subclass, STATextField, that offers this functionality (and much more) with its maxCharacterLength property.


B
Bhavin Bhadani

now how many characters u want just give values

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range   replacementString:(NSString *)string {
     NSUInteger newLength = [textField.text length] + [string length] - range.length;
     return (newLength > 25) ? NO : YES;
  }

K
Kendall Helmstetter Gelner

Use this code here RESTRICTED_LENGTH is length you want to restrict for textfield.

   - (BOOL)textField:(UITextField *)textField     shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == nameTF) {
    int limit = RESTRICTED_LENGTH - 1;
    return !([textField.text length]>limit && [string length] > range.length);
    }
   else
   {
    return YES;
   }

return NO;

}

u
u84six

I did this in Swift for an 8 character limit when using a number pad.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return !(textField.text?.characters.count == MAX_LENGTH && string != "")
}

I had to test for string != "" to allow the delete button to work on the number pad, otherwise it wouldn't allow deleting characters in the text field after it reached its max.


K
Kedu

For Xamarin:

YourTextField.ShouldChangeCharacters = 
delegate(UITextField textField, NSRange range, string replacementString)
        {
            return (range.Location + replacementString.Length) <= 4; // MaxLength == 4
        };

A
Alex Nolasco

I have implemented a UITextField Extension to add a maxLength property to it.

It's based on Xcode 6 IBInspectables, so you can set the maxLength limit on the Interface builder.

Here is the implementation:

UITextField+MaxLength.h

#import <UIKit/UIKit.h>

@interface UITextField_MaxLength : UITextField<UITextFieldDelegate>

@property (nonatomic)IBInspectable int textMaxLength;
@end

UITextField+MaxLength.m

#import "UITextField+MaxLength.h"

@interface UITextField_MaxLength()

@property (nonatomic, assign) id <UITextFieldDelegate> superDelegate;

@end

@implementation UITextField_MaxLength

- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    //validate the length, only if it's set to a non zero value
    if (self.textMaxLength>0) {
        if(range.length + range.location > textField.text.length)
            return NO;

        if (textField.text.length+string.length - range.length>self.textMaxLength) {
            return NO;
        }
    }

    //if length validation was passed, query the super class to see if the delegate method is implemented there
    if (self.superDelegate && [self.superDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
        return [self.superDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    else{
        //if the super class does not implement the delegate method, simply return YES as the length validation was passed
        return YES;
    }
}

- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
    if (delegate == self)
        return;
    self.superDelegate = delegate;
    [super setDelegate:self];
}

//forward all non overriden delegate methods
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.superDelegate  respondsToSelector:aSelector])
        return self.superDelegate;

    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([self.superDelegate respondsToSelector:aSelector])
        return YES;

    return [super respondsToSelector:aSelector];
}
@end