最近几天,一直被一个问题困扰:某个UIViewController(简称VC)的生命周期事件 viewWillAppear
和 viewDidAppear
没有调用。通常这种情况,是没有正确的“放置”VC,比如说只是将VC的view显示,而没有处理VC和 parent VC的关系。但是,我遇到的问题是:在模拟器和真机上,该问题只在iOS13中出现。
该问题具体的复现步骤:
- 在起始页面成功登录后,window 的 rootViewController 切换到首页A(带ASNavigationController)
- 在首页 A push 页面 B
- 页面B除了
viewDidLoad
运行,其它和生命周期相关的函数都不调用
项目使用了 Texture,开发环境是 Xcode11。最开始我的注意力集中在 Texture,猜想是不是没有适配 iOS13。在debug的过程中,在 ASViewController
等文件添加断点一步一步检查后,发现偶尔 VC 的生命周期事件函数完全运行了,这进一步加深了我的判断。事后看,这导致我在错误的路上徘徊了很久,因为当时在GitHub的issue中,没有发现任何相类似的issue,因此我需要自行查看源码进行分析。ASNavigationController 只是添加了visibility 深度的支持,ASViewController的实现中,各个生命周期事件函数都处理到了。 这样花了一天时间,一无所获。
后来检查了起始页,和首页的VC生命周期事件,发现起始页运行正常,而首页 A 中,事件处理很奇怪,顺序如下:
- viewDidLoad
- viewWillAppear
- viewDidAppear
- viewWillAppear
由此,逐渐定位到 rootViewController 切换的部分,这部分的实现如下:
UIView.transition(from: (self.window?.rootViewController?.view)!,
to: splitVC.view,
duration: 1.0,
options: UIView.AnimationOptions.transitionFlipFromLeft) { (result) in
self.window?.rootViewController = splitVC
}
这段代码自从 iOS4.0 就开始用了,在很多开源的项目中有这样的写法。将闭包中的赋值语句移到动画前做一个测试,发现页面 B 的生命周期函数都运行了!知道了原因,那就换一种页面切换方法:
UIView.transition(with: self.window!, duration: 1, options: .transitionFlipFromLeft, animations: {
self.window?.rootViewController = masterNav
}) { (result) in
}
问题完美解决!
反思整个过程,在发现开源项目issue列表中没有类似issue时,就应该考虑项目本身的问题。其次,新建一个样例工程,在排除开源项目责任方面,也是非常有必要的。
Comments