Reputation: 183
I'm a little confused. There are two UIViewControllers
in UINavagationController
's stack. I try to call the method of first UIViewController
within the second UIViewController
. See code below
class VC1: UIViewController {
@objc func method1() {
//not called after tap button
}
}
class VC2: UIViewController {
let button = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(nil, action: #selector(VC1.method1), for: .touchUpInside)
}
}
But method1 isn't called when I tap on the button. What's the problem?
Upvotes: 4
Views: 1076
Reputation: 36427
UIWindow
. Understandably there is a relationship between the presenting and presented view controllers, but it's just a matter of them having references to one another. Their not hooked up through the responder chain pipeline...nextResponder
becomes its ‘parentViewController’———
From nextResponder
docs:
For example, UIView implements this method and returns the UIViewController object that manages it (if it has one) or its superview (if it doesn’t). UIViewController similarly implements the method and returns its view’s superview. UIWindow returns the application object. The shared UIApplication object normally returns nil, but it returns its app delegate if that object is a subclass of UIResponder and has not already been called to handle the event.
Reading this we understand that neither the presentingViewController nor the pushingViewController are a viewController’s superview
Upvotes: 1
Reputation: 536027
The responder chain is based on superviews and parent view controllers. So VC1 is not up the responder chain from VC2. The responder chain from VC2 leads to its parent (the UINavigationController); it does not go by way of any other children of the UINavigationController.
Upvotes: 4
Reputation: 386038
The responder chain, starting from button
, goes through button
's ancestor views and view controllers. Since VC1 and VC2 are separate items in the navigation controller's stack, VC1 is not an ancestor of VC2. They are more like siblings of each other. So VC1 is not in button
's responder chain.
You could just set VC1 as the target of the button action:
let vc1: VC1 = ...
button.addTarget(vc1, action: #selector(VC1.method1), for: .touchUpInside)
But that means VC2 needs reference to the existing VC1 instance. How do you get that reference? It depends on how you created VC2 and pushed it on the navigation stack.
If VC1 creates VC2 in code, then VC1 can just give the new VC2 a reference to self
(the VC1) when creating the VC2.
If you have a storyboard segue from VC1 that pushes VC2 onto the stack, then you need to implement prepare(for: UIStoryboardSegue, sender:)
in VC1, and in that method you need to hand self
(VC1) to the destination of the segue (VC2).
Upvotes: 1