kopacabana
kopacabana

Reputation: 467

How do I targeting selector with addTarget in another class

I try to understand how to control component form one class to another class but that's not working.

class VC:UIViewController {
    override func viewDidLoad() {
        let instance = Test()
        self.view.addSubView(instance.button)
    }
}

class Test:NSObject {
    var button:UIButton!

    override init() {
        button = UIButton(frame:CGRect(x:0, y:0, width:100, height:40))
        button.setTitle(("TEST", for:.normal)
        button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
    }

    @objc func tapButton(_ sender:UIButton) {
        print("TAP Button")
    }
}

When I tapped the button, nothing happens !
I try to change

button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)

with

button.addTarget(nil, action: #selector(tapButton(_:)), for: .touchUpInside)

That's not working !

How to resolve this problem ? Thanks for your help.

Upvotes: 0

Views: 1010

Answers (1)

vacawama
vacawama

Reputation: 154523

You have 3 issues:

  1. instance is a local variable, so it gets deallocated as soon as viewDidLoad() finishes. Make it a property of VC. The button only keeps a weak reference to the object, so when it is deallocated it becomes nil. In cases where the target is nil, UIKit will search up the responder chain for the action method. Since VC doesn't supply a tapButton method, nothing happens when the button is pressed.
  2. You need to call super.init() so that self is available to be used with the button. self can't be created until all properties have been initialized. Because init is an override, you must call super.init() to initialize the properties that NSObject provides before you can use self in the button.
  3. Your frame puts your button in an unaccessible region of the screen. I changed your frame to put the button inside the safe area of the iPhone 11. I also made the button .green so that I could see it.
class VC: UIViewController {
    var instance = Test()          // make instance a property
    
    override func viewDidLoad() {
        // let instance = Test()   // this was a local variable that doesn't hang around
        self.view.addSubview(instance.button)
    }


}


class Test: NSObject {
    var button: UIButton!

    override init() {
        super.init()  // call this so that you can use self below
        button = UIButton(frame:CGRect(x: 100, y: 100, width: 100, height: 40))
        button.setTitle("TEST", for:.normal)
        button.backgroundColor = .green
        button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
    }

    @objc func tapButton(_ sender: UIButton) {
        print("TAP Button")
    }

    // Add deinit to see when this object is deinitialized.  When
    // instance is local to viewDidLoad() this object gets freed
    // when viewDidLoad() finishes.
    deinit {
        print("Oops, the Test object has been deinitialized")
    }
}

Upvotes: 3

Related Questions