iosswiftuitableviewuinavigationcontroller

PushViewController Twice When I double click too quickly


I have the follow code when I call to push the ViewController to detailed chat controller ( 1-to-1 chat). However, if I click too quickly, the view controller will be pushed twice. I see the animation twice. Could anyone point me where the mistake is? The code is from a Youtube lesson (Firebase Chat) from LBTA.

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)
}

Solution

  • What you could do to avoid this issue is to disable the table view user interaction and reenable it after pushing to second view controller.

    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
        })
    }
    

    By default, pushViewController(_:animated:) does not has a completion handler, so as a workaround we could add the follwoing extention to achieve it:

    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() }
        }
    }
    

    Cited from: https://stackoverflow.com/a/33767837/5501940