我的 View Controller 层次结构如下:
- 入口点是一个
UINavigationController
,它的 Root View Controller 是一个普通的UITableViewController
。表格 View 显示字母列表。 - 当用户点击一个单元格时,将触发一个push segue,并且 View 会转换到
ContainerViewController
。它包含一个嵌入式ContentViewController
,其作用是在屏幕上显示所选字母。
Content View Controller 将要显示的字母存储为属性 letter: String
,应在将其 View 推送到屏幕之前设置该属性。
class ContentViewController: UIViewController {
var letter = "-"
@IBOutlet private weak var label: UILabel!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
label.text = letter
}
}
相反,容器 View Controller 不应该知道关于字母的任何信息(内容未知),因为我正试图将其构建为尽可能可重用。
class ContainerViewController: UIViewController {
var contentViewController: ContentViewController? {
return childViewControllers.first as? ContentViewController
}
}
我尝试相应地在我的 TableView Controller 中编写 prepareForSegue()
:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let containerViewController = segue.destinationViewController as? ContainerViewController {
let indexPath = tableView.indexPathForCell(sender as! UITableViewCell)!
let letter = letterForIndexPath(indexPath)
containerViewController.navigationItem.title = "Introducing \(letter)"
// Not executed:
containerViewController.contentViewController?.letter = letter
}
}
但调用此方法时 contentViewController
尚未创建,并且从未设置字母属性。
值得一提的是,当 segue 的目标 View Controller 直接设置在内容 View Controller 上时,这确实有效——在相应地更新 prepareForSegue()
之后。
你知道如何实现吗?
最佳答案
其实我觉得正确的解决方案是依靠内容 View 的程序化实例化,这是我经过深思熟虑后选择的。
以下是我遵循的步骤:
TableView Controller 在 Storyboard 中将推送转场设置为
ContainerViewController
。当用户点击单元格时,它仍然会执行。我在 Storyboard中删除了从容器 View 到
ContentViewController
的嵌入转场,并在我的类中向该容器 View 添加了一个 IB 导出。我为 Content View Controller 设置了一个 Storyboard ID,比如说……
ContentViewController
,这样我们就可以在适当的时候以编程方式实例化它。我实现了自定义容器 View Controller ,如 Apple 的 View Controller Programming Guide 中所述.现在我的
ContainerViewController.swift
看起来像(大部分代码安装并删除了布局约束):class ContainerViewController: UIViewController { var contentViewController: UIViewController? { willSet { setContentViewController(newValue) } } @IBOutlet private weak var containerView: UIView! private var constraints = [NSLayoutConstraint]() override func viewDidLoad() { super.viewDidLoad() setContentViewController(contentViewController) } private func setContentViewController(newContentViewController: UIViewController?) { guard isViewLoaded() else { return } if let previousContentViewController = contentViewController { previousContentViewController.willMoveToParentViewController(nil) containerView.removeConstraints(constraints) previousContentViewController.view.removeFromSuperview() previousContentViewController.removeFromParentViewController() } if let newContentViewController = newContentViewController { let newView = newContentViewController.view addChildViewController(newContentViewController) containerView.addSubview(newView) newView.frame = containerView.bounds constraints.append(newView.leadingAnchor.constraintEqualToAnchor(containerView.leadingAnchor)) constraints.append(newView.topAnchor.constraintEqualToAnchor(containerView.topAnchor)) constraints.append(newView.trailingAnchor.constraintEqualToAnchor(containerView.trailingAnchor)) constraints.append(newView.bottomAnchor.constraintEqualToAnchor(containerView.bottomAnchor)) constraints.forEach { $0.active = true } newContentViewController.didMoveToParentViewController(self) } } }
在我的
LetterTableViewController
类中,我实例化并设置了我的内容 View Controller ,它被添加到容器的 subview Controller 中。这是代码:override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if let containerViewController = segue.destinationViewController as? ContainerViewController { let indexPath = tableView.indexPathForCell(sender as! UITableViewCell)! let letter = letterForIndexPath(indexPath) containerViewController.navigationItem.title = "Introducing \(letter)" if let viewController = storyboard?.instantiateViewControllerWithIdentifier("ContentViewController"), let contentViewController = viewController as? ContentViewController { contentViewController.letter = letter containerViewController.contentViewController = contentViewController } } }
这与一个完全与内容无关的容器 View Controller 完美地工作。顺便说一下,它曾经是在 appDidFinishLaunching:withOptions:
委托(delegate)中实例化 UITabBarController
或 UINavigationController
及其子项的方式方法。
我能看到的唯一缺点:UI 流程不再明确出现在 storyboard 上.
关于ios - 将数据传递给嵌入在容器 View Controller 中的 View Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36570168/