14079_Z
14079_Z

Reputation: 447

Textfield extension error - unrecognized selector sent to instance swift

I made a UITextField extension to crate return button so I can reuse for all the keyboard that don't have return button (like number pad).

What I want: I can custom the return button action to either resignFirstResponder() or becomeFirstResponder() in case of the textfield is at the last or in the middle of other textfield. In this case, I would like it to be becomeFirstResponder() when the user tap return to the firstNameTextField. (note: my textfield IBOutlet is in order)

What I get: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITextField phoneNumberShouldReturnWithSender:]: unrecognized selector sent to instance 0x7f8d07f2b6d0'

Extension

import Foundation
import UIKit

extension UITextField {
    func addReturnButtonOnKeyboard(myAction: Selector?) {
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        doneToolbar.barStyle = .default

        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let next: UIBarButtonItem = UIBarButtonItem(title: "Return", style: .done, target: self, action: myAction)

        let items = [flexSpace, next]
        doneToolbar.items = items
        doneToolbar.sizeToFit()

        self.inputAccessoryView = doneToolbar
    }
}

ViewController

import UIKit
import Alamofire
import IQKeyboardManagerSwift

class NewUserViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var comfirmPasswordTextField: UITextField!
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var phoneNumberTextField: UITextField!
    @IBOutlet weak var firstNameTextField: UITextField!
    @IBOutlet weak var lastNamePasswordTextField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        self.hideKeyboardWhenTappedAround()
        usernameTextField.delegate = self
        passwordTextField.delegate = self
        comfirmPasswordTextField.delegate = self
        emailTextField.delegate = self
        phoneNumberTextField.delegate = self
        firstNameTextField.delegate = self
        lastNamePasswordTextField.delegate = self
        phoneNumberTextField.addReturnButtonOnKeyboard(myAction: #selector(phoneNumberShouldReturn(sender:)))
        IQKeyboardManager.shared.enableAutoToolbar = false
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if let nextResponder = textField.superview?.viewWithTag(textField.tag + 1) {
            nextResponder.becomeFirstResponder()
        } else {
            textField.resignFirstResponder()
        }

        return false
    }

    @objc func phoneNumberShouldReturn(sender: UITextField) {
        firstNameTextField.becomeFirstResponder()
    }    
}

Thanks!!

Upvotes: 3

Views: 1746

Answers (1)

Asperi
Asperi

Reputation: 258621

You specified target in extension so action is send to text field, instead of your controller, instead use like following

1) add target to interface

...
func addReturnButtonOnKeyboard(target: Any?, myAction: Selector?) {
    let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
    doneToolbar.barStyle = .default

    let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, 
          target: nil, action: nil)
    let next: UIBarButtonItem = UIBarButtonItem(title: "Return", style: .done, 
          target: target, action: myAction) // << here !!
    ...

2) pass controller as target

...
lastNamePasswordTextField.delegate = self
phoneNumberTextField.addReturnButtonOnKeyboard(target: self, // << here !!
    myAction: #selector(phoneNumberShouldReturn(sender:)))
...

Upvotes: 4

Related Questions