当我调用将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)
}
答案 0 :(得分:3)
问题是您允许用户多次点击,这导致视图控制器被多次按下。您必须防止这种情况。
因此,一种选择是创建一个全局变量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
来禁止用户多次选择单元格。
答案 1 :(得分: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() }
}
}
答案 2 :(得分:2)
您的代码没有错误,双击一个单元格,这只是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)
}
希望对您有帮助!
答案 3 :(得分:0)
问题是您仅在获得服务器响应后才按下ViewController,并且可以在响应之前再次轻按按钮。
因此,您可以立即推送视图控制器,然后在推送的视图控制器上请求数据,或者使用@Robert Dresler这样的变量来防止“请求”。