【问题标题】:PushViewController Twice When I double click too quickly当我双击太快时,PushViewController 两次
【发布时间】:2019-06-09 14:17:30
【问题描述】:

当我调用将 ViewController 推送到详细聊天控制器(一对一聊天)时,我有以下代码。但是,如果我点击太快,视图控制器将被推送两次。动画看了两遍。谁能指出错误在哪里?代码来自 LBTA 的 Youtube 课程(Firebase 聊天)。

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let message = messages[indexPath.row]
    guard let chatPartnerId = message.chatPartnerId() else {return}

    let ref = Database.database().reference().child("users").child(chatPartnerId)
    ref.observeSingleEvent(of: .value, with: { (snapshot) in
        guard let dictionary = snapshot.value as? [String: AnyObject] else {
            return
        }
        let user = ChatUser(dictionary: dictionary)
        user.id = chatPartnerId
        self.showChatControllerForUser(user)

    }, withCancel: nil)

}

func showChatControllerForUser(_ user: ChatUser) {
    let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
    chatLogController.chatUser = user
    navigationController?.pushViewController(chatLogController, animated: true)
}

【问题讨论】:

    标签: ios swift uitableview uinavigationcontroller


    【解决方案1】:

    问题是您允许用户多次点击,这会导致视图控制器被多次推送。你必须阻止它。

    因此,一种选择是创建一个不允许多次观察的全局变量isObserving

    var isObserving: Bool = false
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
        if !isObserving {
            isObserving = true
            ...
            ref.observeSingleEvent(of: .value, with: { snapshot in
                ...
                self.isObserving = false
                self.showChatControllerForUser(user)
            })
        }
    }
    

    关于更好的用户体验的建议。如果观察需要一些时间,你应该让用户知道有些事情需要时间。例如,您可以开始和停止加载UIActivityIndicatorView。您还可以通过使用表格视图的isUserInteractionEnabled 来禁止用户多次选择单元格。

    【讨论】:

      【解决方案2】:

      问题是您只是在获得服务器响应后才推送 ViewController,并且可以在响应之前再次点击按钮。

      因此,您可以立即推送视图控制器,然后在推送的视图控制器上请求数据,或者使用 @Robert Dresler 所做的变量来阻止“请求”。

      【讨论】:

        【解决方案3】:

        您可以做的就是禁用表格视图用户交互并在推送到第二个视图控制器后重新启用它。

        override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            // add this:
            tableView.isUserInteractionEnabled = false
            let message = messages[indexPath.row]
            guard let chatPartnerId = message.chatPartnerId() else {return}
        
            let ref = Database.database().reference().child("users").child(chatPartnerId)
            ref.observeSingleEvent(of: .value, with: { (snapshot) in
                guard let dictionary = snapshot.value as? [String: AnyObject] else {
                    return
                }
                let user = ChatUser(dictionary: dictionary)
                user.id = chatPartnerId
                self.showChatControllerForUser(user)
        
            }, withCancel: nil)
        
        }
        
        func showChatControllerForUser(_ user: ChatUser) {
            let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
            chatLogController.chatUser = user
            // edit this:
            navigationController?.pushViewController(chatLogController, animated: true)
        
            navigationController?.pushViewController(chatLogController, animated: true, completion: {
                self.tableView.isUserInteractionEnabled = true
            })
        }
        

        默认情况下,pushViewController(_:animated:) 没有完成处理程序,因此作为一种解决方法,我们可以添加以下扩展来实现它:

        extension UINavigationController {
            public func pushViewController(
                _ viewController: UIViewController,
                animated: Bool,
                completion: @escaping () -> Void)
            {
                pushViewController(viewController, animated: animated)
        
                guard animated, let coordinator = transitionCoordinator else {
                    DispatchQueue.main.async { completion() }
                    return
                }
        
                coordinator.animate(alongsideTransition: nil) { _ in completion() }
            }
        }
        

        引用自:https://stackoverflow.com/a/33767837/5501940

        【讨论】:

        • 谢谢。我喜欢这种方法。这样可以避免很多类似我遇到的问题。
        【解决方案4】:

        你的代码没有错误,双击一个单元格它只是 Swift 不检查的东西。

        您可以尝试这样的方法来避免这种行为:

        
        override func viewWillAppear(){
            super.viewWillAppear()
        
            self.view.isUserInteractionEnabled = true // you need to enable user interaction if user comes back
        }
        
        override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
            self.view.isUserInteractionEnabled = false // this will prevent further taps
        
            let message = messages[indexPath.row]
            guard let chatPartnerId = message.chatPartnerId() else {return}
        
            let ref = Database.database().reference().child("users").child(chatPartnerId)
            ref.observeSingleEvent(of: .value, with: { (snapshot) in
                guard let dictionary = snapshot.value as? [String: AnyObject] else {
                    return
                }
                let user = ChatUser(dictionary: dictionary)
                user.id = chatPartnerId
                self.showChatControllerForUser(user)
        
            }, withCancel: nil)
        
        }
        
        func showChatControllerForUser(_ user: ChatUser) {
            let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
            chatLogController.chatUser = user
            navigationController?.pushViewController(chatLogController, animated: true)
        }
        

        希望对你有帮助!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-15
          • 2018-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多