美文网首页专注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