[Swift] How to properly subclass UITextfield and work with its delegate

Consider this:

class ViewController: UIViewController, UITextFieldDelegate  {
    var textfield: UITextField = {
        let tf = UITextField(frame: CGRect(x: 0, y: 0, width: 140, height: 30))
    }()

    override func viewDidLoad() {
        textfield.delegate = self
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("Inside textfield") 
    }
}


When I tap inside the textfield, textFieldDidBeginEditing() is called because the delegate handles that.

What happens if I want to subclass UITextField? How do I handle a tap event inside the subclassed textfield within the subclass? So for example:

class MyTextField: UITextField, UITextFieldDelegate {
    required override init(frame: CGRect) {
        self.delegate = self // CAN'T DO THIS!!!
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("Inside subclassed textfield")
        // This function is NOT executed when I tap inside this subclassed textfield!!
    }
}


The textFieldDidBeginEditing() within the subclass never gets called, I guess because the delegate is not properly set, and I don't know how to set it. It's not possible to do: self.delegate = self

Do I need to create a protocol for MyTextField? If so, how do I hook it all up? What would the code using MyTextField have to do? If I do:

    var subTF = MyTextField(....)
    subTF.delegate = self


Is that .delegate for class UITextField?? or is it for the subclass MyTextField?

Your init is not correct.

You miss call to super.

    required override init(frame: CGRect) {
          super.init(frame: frame)
          delegate = self
    }

why do you add required ? What is the compiler error you get where // CAN'T DO THIS!!!

You should also need the init(coder):

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

With this, textFieldDidBeginEditing works as expected.

Accepted Answer

Thanks for feedback. Don't forget to close the thread.

As for your next question :

the ViewController code which uses MyTextField to also have a UITextFieldDelegate: 

class ViewController: UIViewController, UITextFieldDelegate { 
  override func viewDidLoad() { 
    let myTF = MyTextField( .... ) 
    myTF.delegate = self 
  } 

  func textFieldDidBeginEditing(_ textField: UITextField) {
    print("XXXXX"). // This is printed instead of "Inside subclassed textfield" within the subclass.  
} 

So, if the subclassed textfield's delegate is set to self within the calling code (ViewController in this case), the textFieldDidBeginEditing() inside the subclass is never called.

In general, is there a way to trigger textFieldDidBeginEditing() in both the calling code as well as the one inside the subclass?

Sequence happens as follows:

  • in viewDidLoad, all subviews are loaded.
  • hence the subclassed textfield's delegate is set to itself 
  • but then, you execute code in viewDidLoad and override the delegate to be the class (ViewController)
  • So only this one will be triggered

I do not know of direct mechanism to achieve what you want. And if that was possible, that could make debugging a bit hard.

What you could do:

  • remove the delegate declaration in ViewController for myTF
  • in the MyTextField subclass, post a new notification in textFieldDidBeginEditing
  • make ViewController class subscribe to this notification and handle it.

@Claude31 How do I "close the thread" for my question?

[Swift] How to properly subclass UITextfield and work with its delegate
 
 
Q