Categories
Uncategorized

iOS programming trick: How to use Xcode to set a text field’s maximum length, Visual Studio-style [Updated for Swift 3]

Setting a text box’s maximum length, the Visual Studio way

easy in visual studio

Here’s how you set the maximum number of characters than can be entered into a text box when developing C# and VB applications in Microsoft Visual Studio:

There’s the GUI builder way…

  1. Select the text box.
  2. Set its MaxLength property in the Properties pane.

…and there’s the code way:

myTextBox.maxLength = 3 // or whatever length you like

Setting a text field’s maximum length, the out-of-the-box Xcode way

guy yelling at computer

Here’s how you set the maximum number of characters than can be entered into a text field when developing Objective-C and Swift applications in Xcode:

There isn’t a GUI builder way — just a code way, and it’s a little more work than it needs to be. The typical steps are:

  1. Make the containing view controller a text field delegate (i.e. make it adopt the UITextFieldDelegate protocol) so that it receives messages from all the text fields it contains.
  2. Implement the textfield(_:shouldChangeCharactersInRange:replacementString) method in order to intercept changes to any of the view’s text fields before they’re finalized. This involves:
    • Identifying the text field whose contents were changed, usually with an if or switch statement. If the text field is one whose text we want to limit to a certain length, then:
      • If the change in contents will result in the text not exceeding that length, simply return true.
      • If the change in contents will result in the text exceeding that length,  return false. You may want to take some additional action: for example, if the user tries to paste in more text you want to allow in the text field, you may want to allow a “partial paste” — pasting in the first n characters that will fit in the remaining space — and not reject the pasted text outright.

If you’re curious, I covered this in an earlier article, How to program an iOS text field that takes only numeric input or specific characters with a maximum length.

That’s a lot of work. Isn’t there a way we can get a “max length” property for text fields, like the .NET people?

wouldnt it be nice in xcode

The screen shot above (if you ignore my text annotations) isn’t Photoshoppery on my part. That’s a screen shot of my Xcode showing a selected text field and a corresponding Max Length property editor in the Attributes panel. With just a little coding in a single file, you too can your iOS text fields these goodies that .NET developers have had for ages and set the maximum length of text in a text field in both these ways:

  1. The GUI builder way, and
  2. With a single line of code.

Setting a text field’s maximum length, the improved Xcode way

Start a new project by doing the standard File → New → Project… dance to create a new Single View Application. Open Main.storyboard and place a single text field on the view:

plain text field and attributes inspector

Select the text field and switch to the Attributes Inspector (the inspector panel with the attributes inspector icon icon). The Attributes Inspector lets you edit all sorts of text field properties, but not the maximum length…yet.

new swift file

Use File → New → File… to create a new Swift File. Give it the name TextFieldMaxLengths.swift, and once you’ve created it, enter the following code into it:

import UIKit

extension UITextField {
  
  @IBInspectable var maxLength: Int {
    get {
      return 5
    }
    set {
      
    }
  }

}

Switch back to Main.storyboard, select the text field and look at the Attributes Inspector. You may notice that something’s changed:

enhanced text field and attributes inspector

All we did was create an extension for the UITextField class to give it an extra Int property named maxLength. Marking this property with the @IBInspectable keyword makes the property available to the Attributes Inspector (hence the name — the property can be inspected in Interface Builder).

Now that we’ve added a property to UITextField and made it inspectable within Interface Builder, it’s time to make the property do something.

If you’re using Swift 2.x, update the code in TextFieldMaxLengths.swift to the code below (keep scrolling if you’re using Swift 3):

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

import UIKit

// 1
private var maxLengths = [UITextField: Int]()

// 2
extension UITextField {
  
  // 3
  @IBInspectable var maxLength: Int {
    get {
      // 4
      guard let length = maxLengths[self] else {
        return Int.max
      }
      return length
    }
    set {
      maxLengths[self] = newValue
      // 5
      addTarget(
        self,
        action: #selector(limitLength),
        forControlEvents: UIControlEvents.EditingChanged
      )
    }
  }
  
  func limitLength(textField: UITextField) {
    // 6
    guard let prospectiveText = textField.text
      where prospectiveText.characters.count > maxLength else {
        return
    }
    
    let selection = selectedTextRange
    // 7
    text = prospectiveText.substringWithRange(
      Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
    )
    selectedTextRange = selection
  }
  
}

If you’re using Swift 3, update the code in TextFieldMaxLengths.swift to the code below:

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

import UIKit

// 1
private var maxLengths = [UITextField: Int]()

// 2
extension UITextField {
  
  // 3
  @IBInspectable var maxLength: Int {
    get {
      // 4
      guard let length = maxLengths[self] else {
        return Int.max
      }
      return length
    }
    set {
      maxLengths[self] = newValue
      // 5
      addTarget(
        self,
        action: #selector(limitLength),
        for: UIControlEvents.editingChanged
      )
    }
  }
  
  func limitLength(textField: UITextField) {
    // 6
    guard let prospectiveText = textField.text,
              prospectiveText.characters.count > maxLength
    else {
      return
    }
    
    let selection = selectedTextRange
    // 7
    let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
    text = prospectiveText.substring(to: maxCharIndex)
    selectedTextRange = selection
  }
  
}

Here are my annotations that match the numbered comments in the code:

  1. There are two big things going on in this single line of code, which declares and initializes maxLengths, a dictionary that stores the maximum lengths of text fields:
    • First, there’s the private declaration. In many programming languages, private means “accessible only inside the class”, but in Swift, private means “accessible only inside the source file where they’re defined”. Any code inside TextFieldMaxLengths.swift has access to maxLengths, and any code outside TextFieldMaxLengths.swift does not. By putting maxLengths in the same file as our UITextField extension, we get a place where we can store the maximum lengths of text fields (remember: extensions can only add methods, not properties), and by making it private, we keep other code from messing with it.
    • Then there’s the matter of what to use as the key for the maxLengths dictionary. Swift lets you use anything that conforms to the Hashable protocol as a dictionary key, and UITextField does just that. It makes sense to use the text fields themselves as the keys to the values for their maximum lengths.
  2. Swift extensions let you add new functionality to existing classes, structs, enumerations, and protocols. We’re using an extension to UITextField to add two things:
    • maxLength, a property that lets the programmer set and get the maximum length of a text field, and
    • limitLength, a method called whenever the contents of a text field are changed, and limits the number of characters in that text field.
  3. By marking the maxLength property with @IBInspectable, we make it available to Interface Builder, which then provides an editor for its value in the Attributes Inspector.
  4. Get to know and love the guard statement and the “early return” style of programming; you’re going to see a lot of it in a lot of Swift coding. Here, we’re using guard to filter out cases where no maximum length has been defined for the text field, in which case, we simply return the theoretical maximum string size.
  5. We use addTarget in maxLength‘s setter to ensure that if a text field is assigned a maximum length, the limitLength method is called whenever the text field’s contents change.
  6. Another guard statement. Any case that gets past it is one where the text about to go into the text field is longer than the maximum length.
  7.  Cocoa sometimes likes to make things complicated. This line is the Cocoa way of saying “put the first maxLength characters of prospectiveText into text“. If you’re going to be playing with substrings, you need to get comfortable with Ranges and intervals.

If you include TextFieldMaxLengths.swift in any of your iOS projects, all text fields will have a maxLength property that you can set either GUI builder style in Interface Builder or in code, using myTextField.maxLength = n syntax, just like the .NET people do.

Happy text field coding!

“Text2”: A sample project showing Visual Studio-style text field maximum lengths in action

text2 screenshot

If you’d like to try out the code from this article, I’ve create a project — unimaginatively named Text2 and pictured above— that shows our UITextField extension in action. It’s a quick-and-dirty single view app that presents 4 text fields:

  1. A text field without a set maximum length.
  2. A text field with a 1-character maximum length, with the Max Length property set in Interface Builder.
  3. A text field with a 5-character maximum length, with the maxLength property set in code (in the view controller’s viewDidLoad method).
  4. A text field with a 10-character maximum length, with the Max Length property set in Interface Builder.

Give it a try, learn what makes it tick, and use it as a jumping-off point for your own projects!

xcode download

You can download the project files for this article (27KB zipped) here.

This code was derived from a Swift 1.2 solution posted by Frouo in Stack Overflow. I annotated it, and updated it so that it would be compatible with both Swift 2 and 3.

13 replies on “iOS programming trick: How to use Xcode to set a text field’s maximum length, Visual Studio-style [Updated for Swift 3]”

I found your excellent site while looking for a solution to limiting the number of characters in a text field.
This is exactly what i was looking for – works great in Xcode 7.x, but errors out in Xcode 8 beta 6.
There were 4 errors , and Xcode was able to correct all of them except this last one.

Could you point me in the right direction to solve this?
Thanks!
The Elder Noob

!Error:
Value of type ‘String’ has no member ‘substringWithRange’

text = prospectiveText.substringWithRange(
Range(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength)

I am newbie to swift programming

Wonderfully.. working fine in swift3.0..
Thank you for the help.
Can i do anyother attributes like this.

Hi

I have used your code in a project I am developing so a big thank you, however, swift 4 is complaining about the depreciation
again, will you be producing an update or should I find myself a work around?

Thanks

Steve

Swift 4 tip:

Replace last two lines of the func limitLength with:

text = String(prospectiveText[..<maxCharIndex])
selectedTextRange = selection

Great ! Thanks for this excellent code. Works perfectly with swift 4 , with Carl’s modification

Hi, I loved this article and putting the maximum. I was wondering if you already have or could make an article about making an @IBInspectable minimum character option? I was thinking of using this for a password, for example, where they have to at least have 8 characters. I tried to copy in the maximum text and change words and what they do to make it work for a minimum, but it doesn’t really work. Could you please direct me to that article or could you please make one?

Comments are closed.