Swift 4 UITextField max length in Alert

Viewed 6366

how can I set max length of UITextField in Alert?

What is the latest best practice for this in Swift 4?

This is my code example, but it will crash because UITextField doesn't exist at beginning.

class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
let limitLength = 10
@IBOutlet weak var player1: UIButton!


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

@IBAction func player1Action(_ sender: UIButton) {
    let alertController = UIAlertController(title: "Please enter you name", message: "Maximum 10 characters", preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {
        alert -> Void in
        let textField = alertController.textFields![0] as UITextField
        // do something with textField
        self.player1.setTitle("\(textField.text!)", for: .normal)
    }))
    alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))

    alertController.addTextField(configurationHandler: {(textField : UITextField!) -> Void in
        textField.placeholder = "Name"
    })
    self.present(alertController, animated: true, completion: nil)

}


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    textField.delegate = self

}

Many thanks for your time.

3 Answers
class MaxLengthTextField: UITextField, UITextFieldDelegate {

    private var characterLimit: Int?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        delegate = self
    }

    @IBInspectable var maxLength: Int {
        get {
            guard let length = characterLimit else {
                return Int.max
            }
            return length
        }
        set {
            characterLimit = newValue
        }
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        guard string.characters.count > 0 else {
            return true
        }

        let currentText = textField.text ?? ""
        let prospectiveText = (currentText as NSString).replacingCharacters(in: range, with: string)

        // 1. Here's the first change...
        return allowedIntoTextField(text: prospectiveText)
    }

    // 2. ...and here's the second!
    func allowedIntoTextField(text: String) -> Bool {
        return text.characters.count <= maxLength
    }
}

You can use this class for more than one text field. Just add class MaxLengthTextField to any text field. Then you can modify a number of characters in text field from Storyboard. P.s. this is swift 3.0

You can use some Rx func to manage with it, something like this

let doneAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: { _ in
        block?(alert.textFields?.first?.text)
    })
    alert.addAction(doneAction)
    alert.addTextField { textField in
        textField.autocapitalizationType = .sentences
        textField.placeholder = NSLocalizedString("Placeholder", comment: "")
        textField.rx.text.orEmpty.map {
            if $0.hasPrefix(" ") {
                textField.text = $0.trimmingCharacters(in: .whitespaces)
                return false
            }
            return $0.count > 0 && $0.count < 30
        }.share(replay: 1).bind(to: doneAction.rx.isEnabled).disposed(by: self.disposeBag)
    }

Here I'm connecting textfield with OK button of alert, using Rx to disable button if text starts with whitespace, length = 0, and max length = 30. Don't forget to initialize disposeBag, it must be global

private var disposeBag: DisposeBag = DisposeBag()

and import

import RxSwift
import RxCocoa
Related