在执行功能时单击导航控制器上的后退按钮时应用程序崩溃

Posted

技术标签:

【中文标题】在执行功能时单击导航控制器上的后退按钮时应用程序崩溃【英文标题】:App crashes when clicked on back button on a nav controller while function is executing 【发布时间】:2019-01-20 23:43:19 【问题描述】:

当我单击 VC 上的后退按钮时连接速度很慢,它在访问导航控制器时崩溃。 VC 已被释放,但 setNavBarTitle 在返回另一个视图后执行。我知道函数正在执行,而 VC 已经被释放,但我不确定处理这种情况的最佳方法是什么?

override func viewWillAppear(_ animated: Bool)
    super.viewWillAppear(animated)

    fetchProfile(clientId: clientId)  (result, error) in
        if result?.data != nil  
                if (result?.success)! 
                    self.clientProfile = result!.data!
                    // Avatar
                    let clientImageView = UIImageView()

                    if let url = URL(string: result!.data!.pic_url!) 
                        clientImageView.image = UIImage(named: "System/defaultAvatar")
                        let task = URLSession.shared.dataTask(with: url)  data, response, error in
                            guard let data = data, error == nil else  return 

                            // WARNING: UIImageView.image must be used from main thread only                                
                            clientImageView.image = UIImage(data: data)
                            self.setNavBarTitle(image: clientImageView.image!)
                        
                        task.resume()
                     
                
             
        
    


private func setNavBarTitle(image: UIImage) 
    // Crashes here -> Thread 11: Fatal error: Unexpectedly found nil while unwrapping an Optional value
    let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height

【问题讨论】:

永远不要从后台线程执行 UI 更改。 【参考方案1】:

您可以尝试在方法回调中使用[weak self],因此即使在 VC 释放后调用该方法也不会导致崩溃,因为 self 不会存在:

override func viewWillAppear(_ animated: Bool)
    super.viewWillAppear(animated)

    fetchProfile(clientId: clientId)  [weak self] (result, error) in
        if result?.data != nil  
                if (result?.success)! 
                    self?.clientProfile = result!.data!
                    // Avatar
                    let clientImageView = UIImageView()

                    if let url = URL(string: result!.data!.pic_url!) 
                        clientImageView.image = UIImage(named: "System/defaultAvatar")
                        let task = URLSession.shared.dataTask(with: url)  data, response, error in
                            guard let data = data, error == nil else  return 

                            DispatchQueue.main.async 
                                clientImageView.image = UIImage(data: data)
                                self?.setNavBarTitle(image: clientImageView.image!)
                             


                        
                        task.resume()
                     
                
             
        
    


private func setNavBarTitle(image: UIImage) 
    // Crashes here -> Thread 11: Fatal error: Unexpectedly found nil while unwrapping an Optional value
    guard let navigationBarHeight: CGFloat = self.navigationController?.navigationBar.frame.height else 
        return
    

【讨论】:

"WARNING: UIImageView.image must be used only from main thread" 显示为 self?.setNavBarTitle(image: clientImageView.image!) 行,此行是否也需要进入 DispatchQueue.. ? 是的,对不起,我也会把它放在我的答案中。如果它因弱自我而崩溃,你能试试吗? 德克萨斯州。到目前为止还没有崩溃。不过我会继续测试它。 我还在我的答案中添加了 setNavBarTitle 函数,在您的代码中,您使用 self.navigationController! - 如果 VC 没有导航控制器,最后的感叹号也可能导致应用程序崩溃。我用“?”更新了它在我的回答中,这更安全。 是的,我做到了,它仍然崩溃。我在它周围添加了一个防护装置,以防止它崩溃。它大部分时间都打印“navigationBarHeight nil 返回”。是警卫解决方案还是我们缺少其他东西?守卫让 navigationBarHeight = self.navigationController?.navigationBar.frame.height else print("navigationBarHeight nil 返回") return

以上是关于在执行功能时单击导航控制器上的后退按钮时应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在导航控制器中单击后退按钮时调用哪个方法?

单击后退按钮时,导航堆栈中 VC 的 UINavigationBar 标题颜色不会改变

Flutter单击后退按钮时如何执行

我可以用 xcode 中的“导航控制器后退按钮”传递数据吗

单击隐藏选项卡视图控制器中的后退按钮时如何显示选项卡

单击 Safari 上的后退按钮时使用 React 挂钩强制页面重新加载