从 rootVC 子视图访问 UINavigationController(从 Nib 加载的子视图)

Accessing UINavigationController from rootVC Subview (subview loaded from Nib)

主 ViewController 嵌入在 UINavigationController 子类中,VC 有一个从 nib 加载的子视图。子视图称为 MenuView,并包含将 link 到其他 VC 的 UIButton。

为了让我的主 ViewController 不那么不守规矩,我把所有这些按钮都放在一个子视图中,该子视图从动画菜单打开和关闭的笔尖加载。

但是,我想展示这些中的其他视图控制器,有时 "Modally",有时 "Show"。我所做的似乎有效,但我只想知道这是否合适,或者我是否造成了一些我不知道的不良影响(比如会导致内存泄漏的强引用循环等)。或者有更好的方法吗?

一些代码: 在MenuView.swift

class MenuView: UIView {
    var navigationController = CustomNavigationController()

    func combinedInit(){
        NSBundle.mainBundle().loadNibNamed("MenuViewXib", owner: self, options: nil)
        addSubview(mainView)
        mainView.frame = self.bounds
    }

    @IBAction func optionsAction(sender: AnyObject) {
        self.navigationController.performSegueWithIdentifier("presentOptions", sender: self)
    }

在ViewController.swift

        menuView.navigationController = self.navigationController as! CustomNavigationController

简短回答:不,从层次结构中的某个视图访问视图控制器是不行的,因为这会破坏所有编写的 MVC 规则。


UIView 对象用于在屏幕中显示 UI 组件,并负责正确绘制和布局其子视图。仅此而已。不多也不少。

您应该始终在相关视图实际所属的控制器中处理视图和控制器之间的此类交互。如果你需要从一个视图发送消息到它的视图控制器,你可以使用 delegate approach or NSNotificationCenter class。

如果我处在你的位置,当视图需要来自其视图控制器的一些信息时,我会使用委托。它比使用通知中心更容易理解,因为它可以更容易地跟踪两者之间发生的事情。如果视图控制器需要来自视图的一些信息 (换句话说,反过来),我会选择通知中心。

protocol MenuViewDelegate: class {
  func menuViewDidClick(menuView: MenuView)
}

class MenuView: UIView {
  var weak delegate: MenuViewDelegate?

  @IBAction func optionsAction(sender: AnyObject) {
    delegate?.menuViewDidClick(self)
  }
}

让我们看看视图控制器端发生了什么:

class MenuViewController: UIViewController, MenuViewDelegate {

  override func viewDidLoad() {
    ...
    self.menuView.delegate = self
  }

  func menuViewDidClick(menuView: MenuView) {
    navigationController?.performSegueWithIdentifier("presentOptions", sender: self)
  }
}

有关 iOS 中通信模式的更多信息,您可能想看看这个很棒的 article 以了解它们是如何工作的。