Set the maximum character length of a UITextField
Solution 1
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.
Solution 2
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.
Solution 3
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;}
}
Solution 4
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);
}
Solution 5
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
Comments
-
Justin almost 2 years
How can I set the maximum amount of characters in a
UITextField
on the iPhone SDK when I load up aUIView
? -
avocade over 15 yearsI 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.
-
Chandan Shetty SP over 13 yearsWorks great... For both adding/deleting.
-
Dan Rosenstark over 12 years@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.
-
Ant about 12 yearsUnfortunately, 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.
-
Kyle Clegg almost 12 yearsHow can I set this to just one UITextView on my screen? When I add it to my class it applies to all textviews.
-
Kyle Clegg almost 12 yearsFound 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!
-
eselk over 11 yearsVery nice answer. I would have liked to see one that accepts as much text as possible, instead of not allowing any (like if they try to add 10 chars, and have 9 left, add the first 9) -- like Windows edit controls work. But since I'm not willing to do the work myself, you get my vote good sir! :) (hopefully Apple adds this soon)
-
Dan Abramov over 11 yearsSuch usage of
UIAlertView
s is discouraged by Apple. You should reserve alerts for important messages, and just disallow input, as in accepted answer. -
Hemang over 11 yearsNot a proper way! --- The user will get to know about input size after inserting full string!
-
jowie about 11 yearsGood answer, but the ternary operator is superfluous; you could just put
return newLength <= 25;
-
doxsi about 11 yearsIt was useful for me too. But, If I have 2 different textfield with differente size? ho can I do that?
-
coolcool1994 over 10 yearsWOW thank you soo muchh!! This example sets the maximum length as 25 characters (25 inclusive) just for your reference
-
Morkrom over 10 yearsWhat if you just want the text to not spill over the frame of the textfield; not all characters are the same width, right ?
-
Diogo T about 10 years@Morkrom You're right, take a look on this long post about NSString and Unicode
-
Scott Kohlert about 10 yearsFor anyone having difficulty, make sure that the UITextField's delegate is set to self, and that the <UITextFieldDelegate> is set in the header file.
-
valbu17 almost 10 yearsGreat example!! Thanks! @sickp
-
Justin almost 10 yearsFor the small need of the character limit, I think adding your class would just be overkill.
-
Matt Parkins over 9 yearsWhat is with people having an if statement to return NO or YES? Try this: return !(textField.text.length >= MAX_LENGTH && range.length == 0);
-
Benjohn over 9 yearsThere really is an undo bug as @bcherry mentions – tested with
UITextField
on iPad iOS 8.1. (+1 to comment). Would the author add something about this as it's the top rated answer? I'm happy to do an edit, but mine regularly seem to get rejected! :-) -
Benjohn over 9 yearsI've added a check for the crash and some notes about it drawn from here.
-
Luke over 9 yearsAlthough I did this to remove errors > myTextField.text=[myTextField.text substringToIndex:limit];
-
Jakub Vano about 9 yearsThere is another bug in the system: autocorrection / prediction bypasses
-textField:shouldChangeCharactersInRange:replacementString
delegate method. I think that for completeness answer should mention this. -
Gaurav Gilani about 9 yearsThis will not make you to enter a characters more than or equal to 50.
-
Scott Gardner about 9 yearsGreat 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.
-
6 1 almost 9 yearsThis method can't prevent user input text from apple's auto suggestion above the keyboard.
-
rcw3 almost 9 years@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)?
-
funroll over 8 yearsIn Swift 2.0,
count(textField.text)
needs to betextField.text?.characters.count
-
Danilo Pádua about 8 yearsHow to call this method in objc?
-
User over 7 yearsDoesn't this global variable create memory leaks, by holding references to all the textviews (which reference the superviews up until root-)
-
User over 7 yearsDoesn't the global dictionary create memory leaks, by holding references to all the textviews (which reference the superviews up until root-)
-
Bogdan Onu over 7 yearsFor 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.
-
jesse over 7 yearsIs the bug still exist in latest iOS versions? I can't reproduce it on my iPhone with 10.2 and in simulator with 8.4.
-
jesse over 7 yearsSorry, I rechecked, and yes, it still exists in both my cases. I wasn't able first reproduce it because if you comment out the 'bug-workaround code', it reveals another problem because newLength is unsigned, but the result may be negative. So negative values become very large positive numbers. And comparison returns NO, which hides the bug.
-
Eduardo over 7 yearsClean and perfect solution
-
frouo about 7 years@Ixx I have edited to fix the memory leak issue you pointed out + swift 3. Thanks
-
frouo about 7 yearsWarning, this global variable create memory leaks, by holding references to all the textviews.
-
Jonny about 7 yearsUITextField, not UITextView.
-
Jonny about 7 yearsSwift 3:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
-
Guy Kogus about 7 yearsThis fails in swift when deleting the last character if it consists of multiple bytes (i.e.
range.length
> 1). UnfortunatelyNSRange
and theString
classes are not very compatible, so you can fall into issues like this. You need to convert toNSString
objects. I will post the solution. -
Robert Smith almost 7 yearsGuy, was the "Swift 3.0" solution above updated to handle the "deleting last character" issue? Also I noticed the "Swift 3.0" solution is for textView instead of textField?
-
Fattie over 6 yearsthis is ALMOST TEN YEARS OUT OF DATE. heh! it is now trivial: stackoverflow.com/a/38306929/294884
-
igrek over 6 yearsCan you advise how to properly limit max text input length? i.e. if i limit input to 3 chars and try to input "ででで" which is achieved when i press keyboard buttons "dedede"(each "de" transforms into "で") then i am not able to input the last character, because my validation function considers that to be 4 characters. Here is my validation function:
-(BOOL)textField:(UITextField*)tf shouldChangeCharactersInRange:(NSRange)r replacementString:(NSString*)s {return [tf.text stringByReplacingCharactersInRange:r withString:s].length <= 3;}
This can be reproduced on Japanese - Romaji keyboard -
igrek over 6 yearsthe solution is cutting string length in text field did end editing, hence the author's solution does not handle this case for japanese-romaji keyboard
-
igrek over 6 yearsor this
return textField.text.length < MAX_LENGTH || range.length != 0;
-
Victor Choy over 6 yearsthe most beautiful way to achive it ! Thanks
-
MRizwan33 about 6 yearscan anyone provide me its objective version
-
oddRaven about 6 yearsWhy the
guard
? -
Shan Ye about 6 yearscheck if the text is nil, if you want, you can also use if @oddRaven
-
Nareshkumar Nil over 5 yearsi need same max length added in attribute inspector objective c
-
Carlos Norena over 5 yearsbest answer by far ,,, thanks a lot great solution when there is many textfields that need different lengths
-
Sandip Patel - SM over 5 yearsReally great solution for textfield and textview control character input limit. Its save code lines and time too for developer ...:)
-
Gunhan about 5 yearsHolding 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.
-
Lucas over 4 yearsThis doesn't compile
-
Pocheshire over 4 years@Lucas oh, really? This code is right from the real project. You should try again.
-
Sachin Rana over 4 yearsSuppose 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 constant (25 in your code) to dynamic?
-
Mohamed Hashem over 4 yearsin order to always be able to remove text in case the text field already had text longer the length allowed I replaced ``` swift return newLength <= 25 ``` with ``` swift return newLength <= 25 || newLength < currentCharacterCount ``` that would fix a problem where a user wont be able to remove programatecally assigned text that exceeds the maxLenght
-
Phontaine Judd over 4 yearsThis 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!
-
Jean Raymond Daher about 3 yearsin my case when i use this code and the textField is at its max value, the primaryActionTriggered stops sending events.. so i always return true and do this hack if newLength > maxLength { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in guard let self = self else { return } self.text = self.text?.prefix(maxLength).description } }
-
Ryan Maloney about 3 yearsAs others have mentioned, the Swift code prevents any new characters from being entered after an emoji character is added. Updating both
string.count
instances tostring.utf16.count
fixes this bug. -
Lumii over 2 yearsPlease note that, although this answer gains highest votes, it is highly inaccurate for the reason, it doesn't take input
range
into consideration duringshouldChangeTextIn