Category for Setting Maximum Length of Text in UITextFields on iOS using Objective-C

Unfortunately, there is no property for UITextField that allows controlling the maximum length of text entered into it. Instead, this behavior can, for instance, be achieved by using an appropriate delegate method of the UITextFieldDelegate.

This approach might be handy if it is needed for only few text fields, which have the same maximum length for their texts. However, it can get confusing quickly because of two aspects. Firstly, if you need to add the same delegate method to multiple controller classes, you have redundant code which is always a bad thing. Secondly, if you need different maximum lengths for multiple text fields, you end up with a switch case mess in the delegate method.

Instead, I want to be able setting the maximum length of the text in the storyboard directly in Xcode. This would allow quickly setting the max length for multiple fields in different view controllers. Therefore, I have come up with the following approach. As there is no built-in max length functionality for UITextFields, I employ the ‘User Defined Runtime Attributes’ in Xcode. After selecting the text field for which I want to set the maximum length, I enter the following information in the User Defined Runtime Attributes:
XcodeScreenSnapz012

The goal of the example above is limiting the max length of the text of the selected text field to ten letters. However, if the storyboard would be loaded now in the app, it would crash as there is no such property called maxLength on an UITextField. To add this property to all UITextFields in the app, I add the following category to the project:

UITextField+RuntimeExtension.h

1
2
3
4
5
#import <UIKit/UIKit.h>
 
@interface UITextField (RuntimeExtension)
@property(nonatomic, assign) NSNumber* maxLength;
@end

UITextField+RuntimeExtension.m

1
2
3
4
5
6
7
8
9
10
11
12
13
#import <objc/runtime.h>
 
#import "UITextField+RuntimeExtension.h"
 
static void *MaxLengthKey;
@implementation UITextField (RuntimeExtension)
-(void)setMaxLength:(NSNumber *)maxLength{
    objc_setAssociatedObject(self, &MaxLengthKey, maxLength, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSNumber*)maxLength{
    return objc_getAssociatedObject(self, &MaxLengthKey);
}
@end

This code adds the property maxLength to all UITextFields in the project. The storyboard can now be loaded and executed safely without crashing. However, until now, this functionality does not do anything.

To make the magic happen and control the max length, we need to add the appropriate delegate method to the UITextField’s delegate. As UITextFields are usually added to a UIViewController, I have created the following category implementing the appropriate method from UITextFieldDelegate in a category of UIViewController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import "UIViewController+TextFieldDelegate.h"
#import "UITextField+RuntimeExtension.h"
 
@implementation UIViewController (TextFieldDelegate)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    BOOL shouldChange = YES;
 
    if(textField.maxLength){
        // 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;
            shouldChange = (newLength > [textField.maxLength integerValue]) ? NO : YES;
        if(!shouldChange){
            return shouldChange;
        }
    }
     return shouldChange;
}
@end

This method basically looks if the maxLength property is set on the text field and prevents that the text gets too long. Beware that you have to set the UIViewController in which the text field is used as the text field’s delegate (which Xcode afaik sets by default).

That’s it. Download the categories here and simply drop them into your project. Now you can set max length of a text field easily in Xcode without writing a single line of code. Simply add maxLength as user defined runtime attribute as displayed above. It goes without saying that you can also control the text field’s max length by setting it in the code. You are not forced to use a storyboard. All you have to do for this, is importing UITextField+RuntimeExtension.h in the view controller where you want to set maxLength.

For your convenience, you will find additional runtime properties in the downloaded categories that you can set for a text field. If isDecimalField is set to YES, you can only enter digits into the text field. If isEMailAddress is set, you have to enter a mail address with a valid mail structure. Endless possibilities 🙂

Posted in iOs, Objective-C, Xcode
  • Virat

    Hi,

    I am having problem in this, please help me,

    Here is the hierarchy of my textfield

    – UIViewController – UITableView – UITableViewCell – UITextField.

    As my text field in UITableViewCell the category is not work UIViewController+TextFieldDelegate.h even i am create other category also but that also not work UITableViewController+TextFieldDelegate, UITableViewCell+TextFieldDelegate, UITableView+TextFieldDelegate

    Can you please help me to do the same.

  • well, if i’ve read correctly, your class structure is ok. as long as the text field is used somewhere underneath a UIViewController, the delegate category should automatically apply.

    an alternative problem could be this: »Beware that you have to set the UIViewController in which the text field is used as the text field’s delegate (which Xcode afaik sets by default)« is that the case?

  • Virat

    Thanks Man,

    This is done this is because of local declaration of shouldChangeCharactersInRange..

  • Mauricio

    hi,
    Can you say me if u got a method only for letters? not numbers.
    greetings!

    sorry for my english, i speak spanish, i’m a chilean

  • no, i haven’t got a method for letters. but you can add one easily. add the property isLetter to UITextField+RuntimeExtension and implement it similarly to isEMailAddress.

    Then you treat the field UITextField+RuntimeExtension analog to isDecimalField in – (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string. To detect a character you can use, for instance this snippet I found on SO:

    NSCharacterSet *letterCharset = [NSCharacterSet letterCharacterSet];
    BOOL lettersOnly = [[stringToTest stringByTrimmingCharactersInSet:letterCharset] length] == 0;
    http://stackoverflow.com/questions/15429798/pletter-and-nsregularexpression

  • Mauricio

    Thank’s so much!

    else if(textField.onlyLetters){
    return [self isAlphaNumeric:string];
    }
    – (BOOL) isAlphaNumeric:(NSString *)texto
    {
    NSCharacterSet *alphaSet = [NSCharacterSet letterCharacterSet];
    return [[texto stringByTrimmingCharactersInSet:alphaSet] isEqualToString:@””];
    }

    work really good!