在 swift 中将事件分派到 parent ViewController
dispatch event to parent ViewController in swift
我来自 AS3 背景,所以我可能更容易向您展示我正在尝试使用 AS3 做什么。我有一个 UIViewController(root),里面有一个 ContainerView。我的印象是容器视图的 UIViewController 是 UIViewController(root) 的 child。我想在 child 视图控制器(容器视图)上按下一个按钮,然后将该事件冒泡到 parent(root UIViewController)。在 AS3 中我会有这样的东西
根 Class 创建 child class
var childClass = new ChildClass()
childClass.addEventListener("buttonWasPressed", callThisFunction);
private function callThisFunciton(e:Event):void
{
// move the child view
TweenLite.to(childClass,1,{x:100});
}
在 Child Class 中,我有一个按钮函数可以部署此事件,该事件会冒泡到 parent。
dispatchEvent(new Event("buttonWasPressed", true));
我不确定如何让根 VC 监听那个事件。因为我使用的是 containerView,所以我不确定如何为 child VC 设置出口并听取 child 正在做的事情。我可以控制从 IB 到 VC 的拖动,但这只是为表示容器视图的 UIView 创建了一个出口。当我打印一些文本时,我可以看到 child 视图控制器在 parent VC.
之前首先被实例化
我发现这个 post 我认为指向正确的方向。
https://craiggrummitt.wordpress.com/2014/07/14/communication-between-objects-in-objective-c-and-swift-compared-with-actionscript-part-5/
但是我收到一个错误,很可能是因为我不确定如何建立从 parent VC 到 child VC 的连接容器视图。我环顾四周,似乎找不到太多关于该主题的信息。
感谢您的帮助!
有两种方式:
1) 使用委托协议(推荐)
a) 在您的 child 中,创建一个委托协议,并在 child VC 上创建一个可选的 属性 来保存委托。
protocol ChildViewControllerDelegate {
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
}
b) 在委托协议中创建一个将在按下按钮时调用的方法,并在 child 中实现一个 buttonWasPressed()
方法以在委托上调用此方法。 (您需要将此方法与情节提要中的按钮联系起来)
protocol ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController:ChildViewController)
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
@IBOutlet weak var button: UIButton!
@IBAction func buttonWasPressed(sender: AnyObject) {
self.delegate?.childViewControllerDidPressButton(self)
}
}
c) 让你的 parent 视图控制器符合 child 协议
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
c) 当 child 嵌入到 parent 中时,一种特殊的转场是 运行,称为嵌入转场。你可以在故事板中看到它——它是连接 child 和 parent 的线:
在故事板中为该 segue 添加标识符:
并且在 parent 视图控制器中有一个常量:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
d) 然后在 parent 视图控制器中,覆盖 prepareForSegue()
方法并检查 segue.identifier
是否与您设置的标识符匹配。如果是,那么您可以通过 segue.destinationViewController
获得对 child 视图控制器的引用。将其作为您的 child 视图控制器,然后您可以将 parent 设置为它的委托:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == Constants.embedSegue {
let childViewController = segue.destinationViewController as ChildViewController
childViewController.delegate = self
}
}
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
e) 赢了!
2) 使用 NSNotification 和 NSNotificationCenter
您可以将这些视为类似于 ActionScript 事件,但它们不会像 AS 那样自动在视图层次结构中向上冒泡。相反,通知是通过 NSNotificationCenter
在全球范围内发送的。我更喜欢只在有多个 objects 需要监听一个特定事件时才使用它。
您可以在此处找到有关 NSNotification
和 NSNotificationCenter
的更多信息:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/
嗯,或者你可以使用静态变量,这可能是最直接的方法。
class ParentViewController: UIViewController {
static var instance:ParentViewController?
override func awakeFromNib() {
self.dynamicType.instance = self
}
func parentFunction() {
print("called \(#function) in \(self.dynamicType)")
}
}
class ChildViewController: UIViewController {
func childFunction() {
ParentViewController.instance?.parentFunction()
}
override func viewDidAppear(_ animated: Bool) {
childFunction()
}
}
我来自 AS3 背景,所以我可能更容易向您展示我正在尝试使用 AS3 做什么。我有一个 UIViewController(root),里面有一个 ContainerView。我的印象是容器视图的 UIViewController 是 UIViewController(root) 的 child。我想在 child 视图控制器(容器视图)上按下一个按钮,然后将该事件冒泡到 parent(root UIViewController)。在 AS3 中我会有这样的东西
根 Class 创建 child class
var childClass = new ChildClass()
childClass.addEventListener("buttonWasPressed", callThisFunction);
private function callThisFunciton(e:Event):void
{
// move the child view
TweenLite.to(childClass,1,{x:100});
}
在 Child Class 中,我有一个按钮函数可以部署此事件,该事件会冒泡到 parent。
dispatchEvent(new Event("buttonWasPressed", true));
我不确定如何让根 VC 监听那个事件。因为我使用的是 containerView,所以我不确定如何为 child VC 设置出口并听取 child 正在做的事情。我可以控制从 IB 到 VC 的拖动,但这只是为表示容器视图的 UIView 创建了一个出口。当我打印一些文本时,我可以看到 child 视图控制器在 parent VC.
之前首先被实例化我发现这个 post 我认为指向正确的方向。 https://craiggrummitt.wordpress.com/2014/07/14/communication-between-objects-in-objective-c-and-swift-compared-with-actionscript-part-5/
但是我收到一个错误,很可能是因为我不确定如何建立从 parent VC 到 child VC 的连接容器视图。我环顾四周,似乎找不到太多关于该主题的信息。
感谢您的帮助!
有两种方式:
1) 使用委托协议(推荐)
a) 在您的 child 中,创建一个委托协议,并在 child VC 上创建一个可选的 属性 来保存委托。
protocol ChildViewControllerDelegate {
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
}
b) 在委托协议中创建一个将在按下按钮时调用的方法,并在 child 中实现一个 buttonWasPressed()
方法以在委托上调用此方法。 (您需要将此方法与情节提要中的按钮联系起来)
protocol ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController:ChildViewController)
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
@IBOutlet weak var button: UIButton!
@IBAction func buttonWasPressed(sender: AnyObject) {
self.delegate?.childViewControllerDidPressButton(self)
}
}
c) 让你的 parent 视图控制器符合 child 协议
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
c) 当 child 嵌入到 parent 中时,一种特殊的转场是 运行,称为嵌入转场。你可以在故事板中看到它——它是连接 child 和 parent 的线:
在故事板中为该 segue 添加标识符:
并且在 parent 视图控制器中有一个常量:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
d) 然后在 parent 视图控制器中,覆盖 prepareForSegue()
方法并检查 segue.identifier
是否与您设置的标识符匹配。如果是,那么您可以通过 segue.destinationViewController
获得对 child 视图控制器的引用。将其作为您的 child 视图控制器,然后您可以将 parent 设置为它的委托:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == Constants.embedSegue {
let childViewController = segue.destinationViewController as ChildViewController
childViewController.delegate = self
}
}
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
e) 赢了!
2) 使用 NSNotification 和 NSNotificationCenter
您可以将这些视为类似于 ActionScript 事件,但它们不会像 AS 那样自动在视图层次结构中向上冒泡。相反,通知是通过 NSNotificationCenter
在全球范围内发送的。我更喜欢只在有多个 objects 需要监听一个特定事件时才使用它。
您可以在此处找到有关 NSNotification
和 NSNotificationCenter
的更多信息:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/
嗯,或者你可以使用静态变量,这可能是最直接的方法。
class ParentViewController: UIViewController {
static var instance:ParentViewController?
override func awakeFromNib() {
self.dynamicType.instance = self
}
func parentFunction() {
print("called \(#function) in \(self.dynamicType)")
}
}
class ChildViewController: UIViewController {
func childFunction() {
ParentViewController.instance?.parentFunction()
}
override func viewDidAppear(_ animated: Bool) {
childFunction()
}
}