MT1asli8ghwoi
MT1asli8ghwoi

Reputation: 251

Delegate returns nil when calling method from a didSet

I have a subclass of UITextField used to call two methods after specific textField events. The textField calls the methods in the textField's superclass with a delegate/protocol setup.

class SearchTermCellTextField: UITextField {

    var searchTermCellTextFieldDelegate: SearchTermCellTextFieldDelegate?

    override var text: String? {
        didSet {
            searchTermCellTextFieldDelegate?.textFieldDidChange(self)
        }
    }

    override func deleteBackward() {
        super.deleteBackward()
        searchTermCellTextFieldDelegate?.textFieldReceivedDelete(self)
    }

}

protocol SearchTermCellTextFieldDelegate {

    func textFieldReceivedDelete(_ textField: UITextField)

    func textFieldDidChange(_ textField: UITextField)

}

The delegate is initialized correctly and textFieldReceivedDelete() is called without problem. However, each time textFieldDidChange() is called (in var text { didSet }), searchTermCellTextFieldDelegate has a nil value.

I tried placing searchTermCellTextFieldDelegate?.textFieldDidChange() into a secondary method called by the didSet to see if it would have any effect, but still the same. I tested it from within deleteBackward() — where I don't want it — and searchTermCellTextFieldDelegate? has its non-nil value as expected and it fires fine.

My only guess is that there's something more complex happening within the text variable's { get set } that causes the issue, but beyond that I don't know where to start problem solving.

Does anyone have any insight? Thanks in advance.

Upvotes: 0

Views: 482

Answers (1)

iOS Geek
iOS Geek

Reputation: 4855

Reason - You did Override text of A textField but the function textFieldDidChange that OP want to trigger is based on Editing changed Control Event , Thus Overriding text was not required in your case as text wont be triggered when its value is changed or edited

So, To make that class delegate work you actually need to keep eye on editing change control Event of TextField

Try this

import Foundation
import UIKit


class SearchTermCellTextField: UITextField {

    var TFDelegate : SearchTermCellTextFieldDelegate?

    /// Initialise class
    override init(frame: CGRect) {
        super.init(frame: frame)
        /// Need to add a target to notify class that text did changed
        self.addTarget(self, action: #selector(SearchTermCellTextField.editingChanged), for: .editingChanged)
    }

    /// Coder
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    /// You override Text Not its editing changed
    override var text: String? {
        didSet {
            TFDelegate?.textFieldDidChange(self)
        }
    }

    /// Handler which tells that editing has been changed
    @objc func editingChanged(){
        TFDelegate?.textFieldDidChange(self)
    }

    /// Its Working
    override func deleteBackward() {
        super.deleteBackward()
        TFDelegate?.textFieldReceivedDelete(self)
    }

}

protocol SearchTermCellTextFieldDelegate {

    func textFieldReceivedDelete(_ textField: UITextField)

    func textFieldDidChange(_ textField: UITextField)

}

ViewController class

import UIKit

class ViewController: UIViewController {
    private var myFirstTF : SearchTermCellTextField?
}

/// View Life cycles
extension ViewController
{
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        myFirstTF = SearchTermCellTextField()
        myFirstTF?.TFDelegate = self
        myFirstTF?.placeholder = "Enter Text"

        myFirstTF?.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(myFirstTF!)
        myFirstTF?.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20).isActive=true
        myFirstTF?.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 20).isActive=true
        myFirstTF?.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100).isActive=true
        myFirstTF?.heightAnchor.constraint(equalToConstant: 50)

    }
}

extension ViewController: SearchTermCellTextFieldDelegate
{    
    func textFieldReceivedDelete(_ textField: UITextField) {
        print("delete Recieved")
    }

    func textFieldDidChange(_ textField: UITextField) {
        print("Text:\(textField.text ?? "Empty")")
    }
}

Console Output

enter image description here

Upvotes: 1

Related Questions