Swift中Segue跳转时如何结合依赖注入传递自定义类
Swift Segue传递自定义类的正确实现方式
问题根源分析
你遇到的两个警告原因:
'super.init' isn't called on all paths before returning from initializer:自定义的init(content:)未调用父类初始化方法,UIViewController子类必须在初始化流程中调用对应父类init方法。'required' initializer 'init(coder:)' must be provided by subclass of 'UIViewController':重写指定初始化器后,Swift要求必须实现父类的required初始化器;而通过Storyboard Segue跳转时,系统正是通过init(coder:)实例化ViewController的。
另外你混淆了两种VC实例化逻辑:直接代码初始化(init(content:))和Storyboard/Segue初始化(init(coder:))。Segue跳转时,VC由Storyboard通过init(coder:)创建,自定义init(content:)不会被触发。
方案一:适配Storyboard的依赖注入(非可选属性)
保持content为非可选类型,确保VC必须携带Content才能初始化,同时适配Storyboard流程:
class NextViewController: UIViewController { let content: Content // 用let保证不可变,更安全 // 适配Storyboard的初始化方法,先赋值content再调用父类初始化 init?(coder: NSCoder, content: Content) { self.content = content super.init(coder: coder) } // 强制要求必须带content初始化,防止无参数调用 required init?(coder: NSCoder) { fatalError("必须使用init(coder:content:)初始化,或通过Segue传递content") } // 代码直接初始化的便利方法(可选) convenience init(content: Content) { let storyboard = UIStoryboard(name: "Main", bundle: nil) self.init(coder: storyboard.instantiateViewController(withIdentifier: "NextViewController").coder!)! self.content = content } }
这种方式需要修改跳转逻辑,放弃Segue直接代码初始化VC:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let selectedContent = allcontent[indexPath.item] guard let nextVC = NextViewController(coder: UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NextViewController").coder!, content: selectedContent) else { return } navigationController?.pushViewController(nextVC, animated: true) }
方案二:Segue场景下的简化实现(可选属性)
这是Segue跳转最常用的方式,将content设为可选类型,在prepare(for:sender:)中赋值:
class NextViewController: UIViewController { var content: Content? // 设为可选,适配Storyboard初始化流程 override func viewDidLoad() { super.viewDidLoad() // 使用前做空值校验,避免崩溃 guard let content = content else { fatalError("NextViewController必须在Segue中传递content") } // 直接使用content属性 title = content.title print(content.about) } }
你的第一个ViewController代码可保持不变,仅优化解包逻辑即可:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { performSegue(withIdentifier: "NextView", sender: allcontent[indexPath.item]) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "NextView" { let vc = segue.destination as! NextViewController // 可选绑定避免强制解包风险 if let selectedContent = sender as? Content { vc.content = selectedContent } } }
关于coder的作用解释
init?(coder:)是NSCoding协议方法,当ViewController从Storyboard/XIB加载时,系统通过这个方法解码存储在Storyboard中的视图布局、控件属性等信息,将其还原为ViewController实例。简单来说:Storyboard中的VC都是通过这个初始化方法创建的,必须保证该方法能正确执行(或像方案一那样强制要求带参数初始化)。
内容的提问来源于stack exchange,提问作者Redstain
相关产品推荐
相关产品推荐

