swift - 使用 Storyboard 和自定义视图控制器初始化
问题描述
当以编程方式推送视图控制器时,可以通过 init 方法轻松地进行一些依赖注入:
let dummyVC = DummyVC(dummyManager: DummyManager())
self.pushViewController(dummyVC, animated: true)
使用目标控制器:
class DummyVC: UIViewController {
private let dummyManager: DummyManager
init(dummyManager: DummyManager) {
self.dummyManager = dummyManager
super.init(nibName: nil, bundle: nil)
}
}
前面的代码很好,因为它正确地封装了属性,并且清楚地显示了对外部 API 的依赖关系。
使用 Storyboard 时,我们不能选择调用的 init 方法(调用自定义的 init 方法)。
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let dummyVC = mainStoryboard.instantiateViewControllerWithIdentifier("DummyVC") as! DummyVC
dummyVC.dummyManager = DummyManager() // ERROR: would require dummyManager to have public scope
有没有办法以相同的方式注入依赖项,同时保持属性私有和常量(let)?
解决方案
故事板中的视图控制器总是使用初始化
init?(coder aDecoder: NSCoder)
没有办法解决这个问题。
另一种选择是……</p>
class DummyVC: UIViewController {
private var dummyManager: DummyManager!
func configure(dummyManager: DummyManager) {
self.dummyManager = dummyManager
}
}
然后……</p>
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let dummyVC = mainStoryboard.instantiateViewControllerWithIdentifier("DummyVC") as! DummyVC
dummyVC.configure(dummyManager: DummyManager())
或者
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destination {
case let dummyVC as DummyVC:
dummyVC.configure(dummyManager: DummyManager())
default:
break
}
}
虽然不是完美的(使用let
而不是var
)属性,private
并且隐式展开的可选意味着必须设置它(否则应用程序将在使用时崩溃),并且只能在包含类中发生。
我在整个应用程序中都采用了这一点,并发现它是确保设置所有属性的好方法。只需记住configure
在将属性添加到类时更新 func。
推荐阅读
- swift - 在swiftui中拖放列表行
- ubuntu - 网络不可达 GitHub
- python - 根据来自其他列的过滤器向 Pandas 数据框添加滚动标准偏差
- python - 如何将非结构化格式的文本转换为 JSON 格式
- php - 如何设置 Wordpress 以使用 mailhog 而无需手动安装 Wordpress 的 SMTP 插件
- azure - 使用 terraform destroy 命令删除 azure 资源时出错
- javascript - React Native:图像 URI 不适用于发布 apk
- python - 为什么请求会忽略我的自定义标头字段?
- amazon-web-services - AWS 1 GB EBS 快照存储 100%,但我没有任何快照或 AMI
- r - 根据 R data.table/frame 中的组按日期汇总份额/行数