iOS 响应链和事件
iOS Responder Chain and Events
我有点困惑。 UINavagationController
的堆栈中有两个UIViewControllers
。我尝试在 second UIViewController
中调用 first UIViewController
的方法。请参阅下面的代码
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)
}
}
但是当我点击按钮时没有调用 method1。有什么问题吗?
响应链基于父视图和父视图控制器。所以 VC1 不在 VC2 的响应链上。来自 VC2 的响应链指向它的父节点(UINavigationController);它不会经过 UINavigationController 的任何其他子级。
响应链从 button
开始,经过 button
的祖先视图和视图控制器。由于 VC1 和 VC2 是导航控制器堆栈中的独立项,因此 VC1 不是 VC2 的祖先。他们更像是彼此的兄弟姐妹。所以 VC1 不在 button
的响应链中。
您可以将 VC1 设置为按钮操作的目标:
let vc1: VC1 = ...
button.addTarget(vc1, action: #selector(VC1.method1), for: .touchUpInside)
但这意味着 VC2 需要引用现有的 VC1 实例。你如何获得该参考?这取决于您如何创建 VC2 并将其推送到导航堆栈。
如果 VC1 在代码中创建了 VC2,那么 VC1 在创建 VC2 时可以只给新的 VC2 一个引用 self
(即 VC1)。
如果你有一个来自 VC1 的故事板 segue 将 VC2 压入堆栈,那么你需要在 VC1 中实现 prepare(for: UIStoryboardSegue, sender:)
,并且在该方法中你需要将 self
(VC1) 传递给segue (VC2) 的目的地。
- 推送时,是pushedViewController和navigationController之间的关系。
- 当您模态呈现时,关系是 presentedViewController 和
UIWindow
之间的关系。可以理解,呈现视图控制器和呈现视图控制器之间存在关系,但这只是它们相互引用的问题。他们没有通过响应链管道连接...
- 只有当 viewController 成为另一个 ViewController 的 childViewController 时,它们的响应链才会按照您认为的方式挂钩,这意味着 childViewController 的
nextResponder
成为其“parentViewController”
————
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.
阅读本文我们了解到 presentingViewController 和 pushingViewController 都不是 viewController 的 superview
我有点困惑。 UINavagationController
的堆栈中有两个UIViewControllers
。我尝试在 second UIViewController
中调用 first UIViewController
的方法。请参阅下面的代码
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)
}
}
但是当我点击按钮时没有调用 method1。有什么问题吗?
响应链基于父视图和父视图控制器。所以 VC1 不在 VC2 的响应链上。来自 VC2 的响应链指向它的父节点(UINavigationController);它不会经过 UINavigationController 的任何其他子级。
响应链从 button
开始,经过 button
的祖先视图和视图控制器。由于 VC1 和 VC2 是导航控制器堆栈中的独立项,因此 VC1 不是 VC2 的祖先。他们更像是彼此的兄弟姐妹。所以 VC1 不在 button
的响应链中。
您可以将 VC1 设置为按钮操作的目标:
let vc1: VC1 = ...
button.addTarget(vc1, action: #selector(VC1.method1), for: .touchUpInside)
但这意味着 VC2 需要引用现有的 VC1 实例。你如何获得该参考?这取决于您如何创建 VC2 并将其推送到导航堆栈。
如果 VC1 在代码中创建了 VC2,那么 VC1 在创建 VC2 时可以只给新的 VC2 一个引用 self
(即 VC1)。
如果你有一个来自 VC1 的故事板 segue 将 VC2 压入堆栈,那么你需要在 VC1 中实现 prepare(for: UIStoryboardSegue, sender:)
,并且在该方法中你需要将 self
(VC1) 传递给segue (VC2) 的目的地。
- 推送时,是pushedViewController和navigationController之间的关系。
- 当您模态呈现时,关系是 presentedViewController 和
UIWindow
之间的关系。可以理解,呈现视图控制器和呈现视图控制器之间存在关系,但这只是它们相互引用的问题。他们没有通过响应链管道连接... - 只有当 viewController 成为另一个 ViewController 的 childViewController 时,它们的响应链才会按照您认为的方式挂钩,这意味着 childViewController 的
nextResponder
成为其“parentViewController”
————
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.
阅读本文我们了解到 presentingViewController 和 pushingViewController 都不是 viewController 的 superview