美文网首页专注iOS开发iOS Developer程序员
iOS App 假死,你真的彻底解决这个问题了吗

iOS App 假死,你真的彻底解决这个问题了吗

作者: azhunchen | 来源:发表于2017-03-03 18:24 被阅读973次

现象

最近在我们的 App 中遇到了一个奇葩的问题,在某种场景下,App 会处于假死的状态。

现象:点击屏幕上的任何位置都没有反应,按 Home 键后再打开 App 才能正常

在一个不经意的操作中,终于发现了复现规律,当进入到某个特定的页面后,再 pop 回到 UINavigationController 的第一级时,此时如果在屏幕边缘右滑,问题就出现了。

在我们的 App 中,这个特定的页面是一个包含有 WKWebView 的 ViewController,当时我们模仿了微信在左上角自定义了返回按钮和关闭按钮。由于自定义了 leftBarButtons,所以屏幕边缘右滑返回的功能就失效了。我当时理所当然地在这个页面中添加了以下代码

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer is UIScreenEdgePanGestureRecognizer, !self.webView.canGoBack {
        return true
    }
    return false
}

当我以为优雅地解决了右滑返回的问题时,却发现引入了这么严重的一个问题。。。

解决方案?

于是我 Google 了一下,发现不少人都给出同一个建议,看下面代码

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    let isRoot = viewController == navigationController.viewControllers.first
    navigationController.interactivePopGestureRecognizer?.isEnabled = !isRoot
}

问题是能解决,但是彻底解决问题了吗?

这个方案是去接管 UINavigationControllerdelegate,当在 UINavigationController 的第一级时关闭屏幕边缘右滑功能,反之则开启。

但大家是否有想过这样的问题:

  1. 一般的 iOS App 都有几个 Tab(我们的 App 就有三个 Tab),这就意味着每一个 Tab 的 UINavigationController 都要去做这个处理,万一哪天增加了一个 Tab 但没有做这个处理,那问题同样会遇上。
  2. App 中也经常会做 present 操作,而 present 出来的 ViewController 一般也会在 UINavigationController 里面,同样要处理,否则还会遇上这个问题。

这样才是正解

想到上面两个场景,不寒而栗,另谋其它解决方案!

回想一下问题出现的过程,如果不进入到那个特定的 ViewController,在屏幕边缘右滑是没有问题的,而进入到特定页面再出来问题就出现了,为什么这么奇怪?

由于改的代码量很少,很容易就关注到下面这个地方

navigationController?.interactivePopGestureRecognizer?.delegate

我修改过 delegate 对象,导致问题出现,那原来的 delegate 对象必然不是空的,并且原来的 delegate 对象保证了即使在 UINavigationController 的第一级右滑也不会有假死的问题,所以完美的解决方案其实很简单,先持有原 delegate 对象,最后再修改回去

weak var originalGestureDelegate: UIGestureRecognizerDelegate?
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.originalGestureDelegate = self.navigationController?.interactivePopGestureRecognizer?.delegate
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self.originalGestureDelegate
}

好奇

很好奇,原来的 delegate 对象到底是什么?

打个断点即可看到是 UINavigationInteractiveTransitionBase 的对象,这里来找到了个很好玩的东西,可以看看这篇文章

iOS | 全屏右滑返回详解

要养成一个好习惯

要养成一个好习惯,修改一个级的属性时,一定要先持有这个属性后,再赋值,最终要修改回来

这样说可能有点绕,大家平时在做一些界面的时候,某些界面要隐藏掉导航栏,此时可不能粗暴地在这个页面中将导航栏隐藏掉,正确的做法应该跟上面的解决方案一样,在 viewWillAppear 先持有上一个界面的导航栏状态,在 viewWillDisappear 修改回原来的状态

好慷在家

广告时间

欢迎大家来下载我们的 App 好慷在家,提供专业的保洁保姆服务,38节活动进行中,买份家务包年,宠爱自己一整年!

好慷38节活动

都看完了,不点个赞就走,这样是耍流氓知道吗?👮🏻

相关文章

网友评论

    本文标题:iOS App 假死,你真的彻底解决这个问题了吗

    本文链接:https://www.haomeiwen.com/subject/awprgttx.html