I used a variable to store the text being entered and modifying it by appending the remaining suffix of "mm/dd/yyyy". I am getting the functionality, but if I try to update the cursor to the right position, its creating a problem.
I used the textfield.selectedTextRange to move the cursor from EOF to position I need. But, it is replacing the text entered with last "y" from "mm/dd/yyyy". So If I enter "12" the text changes from mm/dd/yyyy| to "yy|/mm/yyyy" instead of "12|/dd/yyy"
Am I doing it the wrong way?
let dobPlaceholderText = "mm/dd/yyyy"
var enteredDOBText = ""
#objc func textFieldDidChange(_ textField: UITextField){
enteredDOBText.append(textField.text.last ?? Character(""))
let modifiedText = enteredDOBText + dobPlaceholderText.suffix(dobPlaceholderText.count - enteredDOBText.count)
textField.text = modifiedText
setCursorPosition(input: dob.textField, position: enteredDOBText.count)
}
private func setCursorPosition(input: UITextField, position: Int){
let position = input.position(from: input.beginningOfDocument, offset: position)!
input.selectedTextRange = input.textRange(from: position, to: position)
}
The suggestion of matt and aheze in the comments to use textField(_:shouldChangeCharactersIn:replacementString:) is very promising in such use cases.
The procedure could look something like this:
determine the resulting text as it would look like after the user input and filter out all non-numeric characters
apply the pattern as defined in your dobPlaceholderText
set the result in the UIText field
determine and set new cursor position
In source code it could look like this:
let dobPlaceholderText = "mm/dd/yyyy"
let delims = "/"
let validInput = "0123456789"
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let filteredText = filtered(textField.text, range: range, replacement: string)
let newText = applyPattern(filteredText, pattern: Array(dobPlaceholderText))
textField.text = newText
let newPosition = newCursorPosition(range: range, replacement: string, newText: newText)
setCursorPosition(input: textField, position: newPosition)
return false
}
The actual implementation of the three methods filtered, applyPattern and newCursorPosition depends on the exact detail behavior you want to achieve. This is just a sample implementation, use something that reflects your requirements.
private func filtered(_ text: String?,range:NSRange, replacement: String) -> Array<Character> {
let textFieldText: NSString = (text ?? "") as NSString
let textAfterUpdate = textFieldText.replacingCharacters(in: range, with: replacement)
var filtered = Array(textAfterUpdate.filter(validInput.contains))
if filtered.count >= dobPlaceholderText.count {
filtered = Array(filtered[0..<dobPlaceholderText.count])
}
return filtered
}
private func applyPattern(_ filtered: Array<Character>, pattern: Array<Character>) -> String {
var result = pattern
var iter = filtered.makeIterator()
for i in 0..<pattern.count {
if delims.contains(pattern[i]) {
result[i] = pattern[i]
} else if let ch = iter.next() {
result[i] = ch
} else {
result[i] = pattern[i]
}
}
return String(result)
}
private func newCursorPosition(range: NSRange, replacement: String, newText: String) -> Int {
var newPos = 0
if replacement.isEmpty {
newPos = range.location
}
else {
newPos = min(range.location + range.length + 1, dobPlaceholderText.count)
if newPos < dobPlaceholderText.count && delims.contains(Array(newText)[newPos]) {
newPos += 1
}
}
return newPos
}
Demo
I am developing a Point Of Sales app.
So I would like to
Let's say User input 100000 but I want it to automatically show up 100,000. and 1000000 become 1,000,000
The second problem is that, I don't want user to be able to input . themselves.
Third problem is that since this is money, we can't let user to enter 0 in the beginning.
Any ideas?
So far I have managed to restrict the input to decimal digits only
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let numberSet: NSCharacterSet = NSCharacterSet.decimalDigitCharacterSet().invertedSet;
return string.stringByTrimmingCharactersInSet(numberSet).length > 0 || string == "";
}
Thank you very much
P.S.: I do not need any decimal places, also we need to take into account when the user change the cursor position when hitting backspace
Xcode 9 • Swift 4
import UIKit
class IntegerField: UITextField {
var lastValue = 0
let maxValue = 1_000_000_000
var amount: Int {
if let newValue = Int(string.digits), newValue < maxValue {
lastValue = newValue
} else if !hasText {
lastValue = 0
}
return lastValue
}
override func didMoveToSuperview() {
textAlignment = .right
keyboardType = .numberPad
text = Formatter.decimal.string(for: amount)
addTarget(self, action: #selector(editingChanged), for: .editingChanged)
}
#objc func editingChanged(_ textField: UITextField) {
text = Formatter.decimal.string(for: amount)
}
}
extension NumberFormatter {
convenience init(numberStyle: Style) {
self.init()
self.numberStyle = numberStyle
}
}
struct Formatter {
static let decimal = NumberFormatter(numberStyle: .decimal)
}
extension UITextField {
var string: String { return text ?? "" }
}
extension String {
private static var digitsPattern = UnicodeScalar("0")..."9"
var digits: String {
return unicodeScalars.filter { String.digitsPattern ~= $0 }.string
}
}
extension Sequence where Iterator.Element == UnicodeScalar {
var string: String { return String(String.UnicodeScalarView(self)) }
}
Simple thing i came up with fully tested on Swift 2.0
you can use the any of the textField delegate see which one suites you
let price = Int(textField.text!)
let _curFormatter : NSNumberFormatter = NSNumberFormatter()
_curFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
_curFormatter.currencyCode = "INR"
_curFormatter.maximumFractionDigits = 0
let total = _curFormatter.stringFromNumber(price!)
textField.text = total
This code works perfectly, and I can't key in anything other than integers, even when I try to paste it in.
I'd like to add one more refinement, which is to limit the length of the input. Here's my code:
func initializeTextFields()
{
APTeams.delegate = self
APTeams.keyboardType = UIKeyboardType.NumberPad
APRounds.delegate = self
APRounds.keyboardType = UIKeyboardType.NumberPad
APBreakers.delegate = self
APBreakers.keyboardType = UIKeyboardType.NumberPad
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
if text == "" {
return true
}
if let _ = Int(text) {
return true
}
else {
return false
}
}
What do I have to add to it to achieve this? The maximum input length for all the TextFields should be <= 4.
BTW, all code is in Swift 2. From problems I faced when trying to implement answers to questions I've asked before, I gather that some of the methods are different.
count(textField.text) is deprecated in SWIFT 2.0
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let textField = textField as? UITextField {
if (range.length + range.location > textField.text!.characters.count) {
return false;
}
let newLength = textField.text!.characters.count + string.characters.count - range.length;
switch(textField.tag) { //In case you want to handle multiple textfields
case Constants.TAG1:
return newLength <= 20;
case Constants.TAG2:
return newLength <= 30;
default:
return newLength <= 15;
}
}
return true;
}
Write the condition in textfield delegate method as:-
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
if (count(textField.text) > 4 && range.length == 0)
{
return false // return NO to not change text
}
else
{
}
write all your code part in else part.
The delegate methods or an NSFormatter such as NSNumberFormatter.
The formatter is the most appropriate generally as it also provides localization support.
I know its bit too late but still I want share it too, I found a way which is much easier to set a limit character for an textfield in swift development.
Here is the code:-
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: .editingChanged)
}
}
#objc func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text, prospectiveText.count > maxLength else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
#if swift(>=4.0)
text = String(prospectiveText[..<maxCharIndex])
#else
text = prospectiveText.substring(to: maxCharIndex)
#endif
selectedTextRange = selection
}
}
and just set the limit through the panel.
Image:
Just try this to limit the length of TF
Editing changed Action Outlet of TF
#IBAction func otpTF2EditingChnaged(_ sender: UITextField) {
if (sender.text?.count == 1) {
otpTF3.becomeFirstResponder()
}
checkMaxLength(textField: sender , maxLength: 1)
}
Function That will limit the length
private func checkMaxLength(textField: UITextField!, maxLength: Int) {
if (textField.text!.count > maxLength) {
textField.deleteBackward()
}
}
I know there are other topics on this, but I can't seem to find out how to implement it.
I'm trying to limit a UITextField to only five characters.
Preferably alphanumeric, -, ., and _.
I've seen this code:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text
let newString: NSString =
currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
and
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let length = count(textField.text.utf16) + count(string.utf16) - range.length
return length <= 10
}
How can I actually implement it? Which "textfield" should I swap out for my custom named UITextField?
Your view controller should conform to UITextFieldDelegate, like below:
class MyViewController: UIViewController, UITextFieldDelegate {
}
Set the delegate of your textfield: myTextField.delegate = self
Implement the method in your view controller:
textField(_:shouldChangeCharactersInRange:replacementString:)
All together:
class MyViewController: UIViewController, UITextFieldDelegate // Set delegate to class
#IBOutlet var mytextField: UITextField // textfield variable
override func viewDidLoad() {
super.viewDidLoad()
mytextField.delegate = self // set delegate
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text
let newString: NSString = currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
For Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 1
let currentString: NSString = (textField.text ?? "") as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
For Swift 5
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 1
let currentString = (textField.text ?? "") as NSString
let newString = currentString.replacingCharacters(in: range, with: string)
return newString.count <= maxLength
}
Allowing only a specified set of characters to be entered into a given text field
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var result = true
if mytextField == textField {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789.-").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
result = replacementStringIsLegal
}
}
return result
}
How to program an iOS text field that takes only numeric input with a maximum length
Modern Swift
Note that a lot of the example code online is extremely out of date.
Paste the following into any Swift file in your project, example "Handy.swift".
This fixes one of the silliest problems in iOS:
Your text fields now have a .maxLength.
It is completely OK to set that value in storyboard or set in code while the app is running.
// Handy.swift
import UIKit
private var __maxLengths = [UITextField: Int]()
extension UITextField {
#IBInspectable var maxLength: Int {
get {
guard let l = __maxLengths[self] else {
return 150 // (global default-limit. or just, Int.max)
}
return l
}
set {
__maxLengths[self] = newValue
addTarget(self, action: #selector(fix), for: .editingChanged)
}
}
func fix(textField: UITextField) {
let t = textField.text
textField.text = t?.prefix(maxLength).string
}
}
It's that simple.
An even simpler one-off version...
The above fixes all text fields in the whole project.
If you just want one particular text field to simply be limited to say "4", and that's that...
class PinCodeEntry: UITextField {
override func didMoveToSuperview() {
super.didMoveToSuperview()
addTarget(self, action: #selector(fixMe), for: .editingChanged)
}
#objc private func fixMe() { text = text?.prefix(4) }
}
That's all there is to it.
(Here's a similar very useful tip relating to UITextView,
https://stackoverflow.com/a/42333832/294884 )
In Swift 4, simply use:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return range.location < 10
}
The same way Steven Schmatz did it but using Swift 3.0 :
//max Length
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
Simple solution without using a delegate:
TEXT_FIELD.addTarget(self, action: #selector(editingChanged(sender:)), for: .editingChanged)
#objc private func editingChanged(sender: UITextField) {
if let text = sender.text, text.count >= MAX_LENGHT {
sender.text = String(text.dropLast(text.count - MAX_LENGHT))
return
}
}
For Swift 5:
Just write one line to set the maximum character length:
self.textField.maxLength = 10
For more details, see Max character limit of UITextField and allowed characters Swift. (Also credited.)
I think an extension is more handy for this. See the full answer here.
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
}
}
My Swift 4 version of shouldChangeCharactersIn
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
guard let preText = textField.text as NSString?,
preText.replacingCharacters(in: range, with: string).count <= MAX_TEXT_LENGTH else {
return false
}
return true
}
Other solutions posted previously produce a retain cycle due to the textfield map. Besides, the maxLength property should be nullable if not set instead of artificial Int.max constructions; and the target will be set multiple times if maxLength is changed.
Here an updated solution for Swift4 with a weak map to prevent memory leaks and the other fixes
private var maxLengths = NSMapTable<UITextField, NSNumber>(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory)
extension UITextField {
var maxLength: Int? {
get {
return maxLengths.object(forKey: self)?.intValue
}
set {
removeTarget(self, action: #selector(limitLength), for: .editingChanged)
if let newValue = newValue {
maxLengths.setObject(NSNumber(value: newValue), forKey: self)
addTarget(self, action: #selector(limitLength), for: .editingChanged)
} else {
maxLengths.removeObject(forKey: self)
}
}
}
#IBInspectable var maxLengthInspectable: Int {
get {
return maxLength ?? Int.max
}
set {
maxLength = newValue
}
}
#objc private func limitLength(_ textField: UITextField) {
guard let maxLength = maxLength, let prospectiveText = textField.text, prospectiveText.count > maxLength else {
return
}
let selection = selectedTextRange
text = String(prospectiveText[..<prospectiveText.index(from: maxLength)])
selectedTextRange = selection
}
}
I give a supplementary answer based on #Frouo. I think his answer is the most beautiful way. Because it's a common control we can reuse. And there isn't any leak problem here.
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)
}
}
// The method is used to cancel the check when using
// the 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
}
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
}
}
Simply just check with the number of characters in the string
Add a delegate to view controller and assign the delegate
class YorsClassName : UITextFieldDelegate {
}
Check the number of characters allowed for the text field
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text?.count == 1 {
return false
}
return true
}
Note: Here I checked for only characters allowed in textField.
TextField Limit Character After Block the Text in Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range:
NSRange,replacementString string: String) -> Bool
{
if textField == self.txtDescription {
let maxLength = 200
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
return true
}
I have something to add to Alaeddine's answer:
Your view controller should conform to UITextFieldDelegate
class MyViewController: UIViewController, UITextViewDelegate {
}
Set the delegate of your textfield:
To set the delegate, you can control drag from the textfield to your view controller in the storyboard. I think this is preferable to setting it in code
Implement the method in your view controller:
textField(_:shouldChangeCharactersInRange:replacementString:)
Update for Fattie's answer:
extension UITextField {
// Runtime key
private struct AssociatedKeys {
// Maximum length key
static var maxlength: UInt8 = 0
// Temporary string key
static var tempString: UInt8 = 0
}
// Limit the maximum input length of the textfiled
#IBInspectable var maxLength: Int {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.maxlength) as? Int ?? 0
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.maxlength, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
addTarget(self, action: #selector(handleEditingChanged(textField:)), for: .editingChanged)
}
}
// Temporary string
private var tempString: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.tempString) as? String
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.tempString, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
// When the text changes, process the amount of text in the input
// box so that its length is within the controllable range.
#objc private func handleEditingChanged(textField: UITextField) {
// Special processing for the Chinese input method
guard markedTextRange == nil else { return }
if textField.text?.count == maxLength {
// Set lastQualifiedString where text length == maximum length
tempString = textField.text
} else if textField.text?.count ?? 0 < maxLength {
// Clear lastQualifiedString when text length > maxlength
tempString = nil
}
// Keep the current text range in arcgives
let archivesEditRange: UITextRange?
if textField.text?.count ?? 0 > maxLength {
// If text length > maximum length, remove last range and to move to -1 postion.
let position = textField.position(from: safeTextPosition(selectedTextRange?.start), offset: -1) ?? textField.endOfDocument
archivesEditRange = textField.textRange(from: safeTextPosition(position), to: safeTextPosition(position))
} else {
// Just set current select text range
archivesEditRange = selectedTextRange
}
// Main handle string maximum length
textField.text = tempString ?? String((textField.text ?? "").prefix(maxLength))
// Last configuration edit text range
textField.selectedTextRange = archivesEditRange
}
// Get safe textPosition
private func safeTextPosition(_ optionlTextPosition: UITextPosition?) -> UITextPosition {
/* beginningOfDocument -> The end of the the text document. */
return optionlTextPosition ?? endOfDocument
}
}
Set the delegate of your textfield:
textField.delegate = self
Implement the method in your view controller:
// MARK: Text field delegate
extension ViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return range.location < maxLength (maxLength can be any maximum length you can define)
}
}
Here's a Swift 3.2+ alternative that avoids unnecessary string manipulation. In this case, the maximum length is 10:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = textField.text ?? ""
return text.count - range.length + string.count <= 10
}
This answer is for Swift 4 and is pretty straightforward with the ability to let backspace through.
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
return textField.text!.count < 10 || string == ""
}
This is working In Swift 4
Step 1: Set UITextFieldDelegate
class SignUPViewController: UIViewController , UITextFieldDelegate {
#IBOutlet weak var userMobileNoTextFiled: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
Step 2: Set the delegate
userMobileNoTextFiled.delegate = self // Set delegate
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// guard let text = userMobileNoTextFiled.text else { return true }
// let newLength = text.count + string.count - range.length
// return newLength <= 10
// }
Step 3: Call the function
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 10 // Set your need
let currentString: NSString = textField.text! as NSString
let newString: NSString =
currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
}
I use these steps. First set the delegate text field in viewdidload.
override func viewDidLoad() {
super.viewDidLoad()
textfield.delegate = self
}
And then shouldChangeCharactersIn after you include UITextFieldDelegate.
extension viewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newLength = (textField.text?.utf16.count)! + string.utf16.count - range.length
if newLength <= 8 {
return true
}
else {
return false
}
}
}
Just in case, don't forget to guard the range size before applying it to the string. Otherwise, you will get a crash if the user will do this:
Type maximum length text
Insert something (nothing will be inserted due to the length limitation, but iOS doesn't know about it)
Undo insertion (you get a crash, because the range will be greater than the actual string size)
Also, using iOS 13 users can accidentally trigger this by gestures
I suggest you add to your project this
extension String {
func replace(with text: String, in range: NSRange) -> String? {
// NOTE: NSString conversion is necessary to operate in the same symbol steps
// Otherwise, you may not be able to delete an emoji, for example
let current = NSString(string: self)
guard range.location + range.length <= current.length else { return nil }
return current.replacingCharacters(in: range, with: text)
}
}
And use it like this:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
guard let newText = textView.text.replace(with: text, in: range) else { return false }
return newText.count < maxNumberOfCharacters
// NOTE: You may wanna trim the new text instead,
// so the user will able to shove his long text at least partially
}
Otherwise, you will constantly be getting crashed in your app.
If you have multiple textField that have various length checks on one page I've found an easy and short solution.
class MultipleTextField: UIViewController {
let MAX_LENGTH_TEXTFIELD_A = 10
let MAX_LENGTH_TEXTFIELD_B = 11
lazy var textFieldA: UITextField = {
let textField = UITextField()
textField.tag = MAX_LENGTH_TEXTFIELD_A
textField.delegate = self
return textField
}()
lazy var textFieldB: UITextField = {
let textField = UITextField()
textField.tag = MAX_LENGTH_TEXTFIELD_B
textField.delegate = self
return textField
}()
}
extension MultipleTextField: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return (range.location < textField.tag) && (string.count < textField.tag)
}
}
lazy var textField: UITextField = {
let textField = UITextField()
textField.addTarget(self, #selector(handleOnEditing), for .editingChanged)
return textField
}()
//Set Delegate in ViewDidLoad
textField.delegate = self
#objc func handleOnEditing() {
let text = textField.text ?? ""
let limit = 10
textField.text = String(text.prefix(limit))
}