Swift 3 MVP模式初始化Presenter时类型转换异常求助
你遇到的这个问题本质是Swift类初始化阶段的self特殊性导致的,咱们一步步拆解:
为什么会出现那个奇怪的类型?
你看到的(WirelessSpeakersViewController) -> () -> WirelessSpeakersViewController其实是Swift在类存储属性初始化时,self的特殊表现类型。在这个阶段,ViewController的实例还没有完全初始化完成,self并不是一个完整的WirelessSpeakersViewController对象,而是一个指向类构造逻辑的引用——简单说就是“还没造好的半成品”,自然无法被转换成WirelessSpeakersView协议类型,强制转换就会触发运行时崩溃。
问题根源
你直接在存储属性初始化时写WirelessSpeakersPresenter(view: self as! WirelessSpeakersView),这时候self还处于构造过程中,还没有完全实现WirelessSpeakersView协议(虽然你在类里写了协议方法,但只有当实例完全初始化后,Swift才会确认它符合协议)。强制转换在这里完全是多余且危险的操作。
解决方案
有两种简单可靠的方式来修复这个问题:
1. 延迟初始化Presenter到viewDidLoad
把Presenter改成隐式解包可选类型,在ViewController完全初始化后的viewDidLoad方法里创建Presenter:
class WirelessSpeakersViewController: UIViewController, WirelessSpeakersView { private var presenter: WirelessSpeakersPresenter! override func viewDidLoad() { super.viewDidLoad() // 此时self已经是完全初始化的实例,自动符合WirelessSpeakersView协议 presenter = WirelessSpeakersPresenter(view: self) } // 实现WirelessSpeakersView的所有方法 func present() { /* ... */ } func goBack() { /* ... */ } func alertSaveFailed() { /* ... */ } }
2. 使用懒加载属性
懒加载的属性会在第一次被访问时才初始化,这时候self已经完成了初始化,是完整的实例:
class WirelessSpeakersViewController: UIViewController, WirelessSpeakersView { // lazy关键字确保初始化时self已经完全可用 private lazy var presenter: WirelessSpeakersPresenter = WirelessSpeakersPresenter(view: self) // 实现WirelessSpeakersView的所有方法 func present() { /* ... */ } func goBack() { /* ... */ } func alertSaveFailed() { /* ... */ } }
这两种方式都不需要任何强制类型转换,因为当Presenter被初始化时,self已经是一个完全符合WirelessSpeakersView协议的实例了。
内容的提问来源于stack exchange,提问作者Arnie Schwarzvogel

