UIViewController生命周期没有完整运行的解决

最近几天,一直被一个问题困扰:某个UIViewController(简称VC)的生命周期事件 viewWillAppearviewDidAppear 没有调用。通常这种情况,是没有正确的“放置”VC,比如说只是将VC的view显示,而没有处理VC和 parent VC的关系。但是,我遇到的问题是:在模拟器和真机上,该问题只在iOS13中出现。
该问题具体的复现步骤:

  1. 在起始页面成功登录后,window 的 rootViewController 切换到首页A(带ASNavigationController)
  2. 在首页 A push 页面 B
  3. 页面B除了 viewDidLoad 运行,其它和生命周期相关的函数都不调用

项目使用了 Texture,开发环境是 Xcode11。最开始我的注意力集中在 Texture,猜想是不是没有适配 iOS13。在debug的过程中,在 ASViewController等文件添加断点一步一步检查后,发现偶尔 VC 的生命周期事件函数完全运行了,这进一步加深了我的判断。事后看,这导致我在错误的路上徘徊了很久,因为当时在GitHub的issue中,没有发现任何相类似的issue,因此我需要自行查看源码进行分析。ASNavigationController 只是添加了visibility 深度的支持,ASViewController的实现中,各个生命周期事件函数都处理到了。 这样花了一天时间,一无所获。
后来检查了起始页,和首页的VC生命周期事件,发现起始页运行正常,而首页 A 中,事件处理很奇怪,顺序如下:

  1. viewDidLoad
  2. viewWillAppear
  3. viewDidAppear
  4. 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