如何在不打印两次数据的情况下重新加载 UITableView?

How to reload UITableView without printing data twice?

我有一个用作 UITableView 的 SlackTextViewController 视图。我正在使用 public 字符串在 "states" 之间切换,允许它读取特定状态下的一组数据和另一状态下的另一组数据。问题是当我来回切换到原始状态时,它打印数据 2、3、4 次;和我来回一样多。我正在从 Firebase 服务器加载数据,我认为这可能是 Firebase 问题。这是我的代码...

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

    if chatState == "ALL"
    {
        self.globalChat()
    }else if chatState == "LOCAL"
    {
        self.localChat()
    }
}

override func viewDidDisappear(animated: Bool) {
    self.messageModels.removeAll()
    tableView.reloadData()
    ref.removeAllObservers()
}

func chatACTN()
{
    if chatState == "ALL"
    {
        self.viewWillAppear(true)

    }else if chatState == "LOCAL"
    {
        self.viewWillAppear(true)
    }
}

func globalChat()
{
    self.messageModels.removeAll()
    tableView.reloadData()

    let globalRef = ref.child("messages")
    globalRef.keepSynced(true)
    globalRef.queryLimitedToLast(100).observeEventType(.ChildAdded, withBlock: { (snapshot) -> Void in
        if snapshot.exists()
        {
            let names = snapshot.value!["name"] as! String
            let bodies = snapshot.value!["body"] as! String
            let avatars = snapshot.value!["photo"] as! String
            let time = snapshot.value!["time"] as! Int

            let messageModel = MessageModel(name: names, body: bodies, avatar: avatars, date: time)
            self.messageModels.append(messageModel)
            self.messageModels.sortInPlace{ [=10=].date > .date }
        }
        self.tableView.reloadData()
    })
}

func localChat()
{
    self.messageModels.removeAll()
    tableView.reloadData()

    print("LOCAL")
}

问题是每次调用 globalChat() 时都会创建另一个新的观察者,这会导致多个观察者将相同的项目添加到 self.messageModels。这就是为什么您在切换到全局状态时会多次看到数据。

既然你想在每次切换到全局时清除聊天并加载最后 100 个,那么当你切换到“本地”时保持观察者处于活动状态是没有意义的。

切换到 Local 时只需移除观察器,这应该可以解决您的问题。


来自 firebase 文档:

- (void) removeAllObservers

Removes all observers at the current reference, but does not remove any observers at child references.

removeAllObservers must be called again for each child reference where a listener was established to remove the observers.

因此,ref.removeAllObservers() 不会移除 ref.child("messages") 级别的观察者。


localChat 函数的开头使用 ref.child("messages").removeAllObservers 删除您在 globalChat 中创建的观察者,如果您只在这个级别处理这个观察者,但是如果您在同一级别上有更多,或者您认为将来可能会添加更多,最好和最安全的方法是删除您创建的特定观察者。为此,您应该使用从启动观察者返回的句柄。像这样修改您的代码:

var globalChatHandle : FIRDatabaseHandle?

func globalChat()
{
    self.messageModels.removeAll()
    tableView.reloadData()
    
    ref.child("messages").keepSynced(true)
    globalChatHandle = ref.child("messages").queryLimitedToLast(100).observeEventType(.ChildAdded, withBlock: { (snapshot) -> Void in
        if snapshot.exists()
        {
            let names = snapshot.value!["name"] as! String
            let bodies = snapshot.value!["body"] as! String
            let avatars = snapshot.value!["photo"] as! String
            let time = snapshot.value!["time"] as! Int
            
            let messageModel = MessageModel(name: names, body: bodies, avatar: avatars, date: time)
            self.messageModels.append(messageModel)
            self.messageModels.sortInPlace{ [=10=].date > .date }
        }
        self.tableView.reloadData()
    })
}

func localChat()
{
    if globalChatHandle != nil {
        ref.child("messages").removeObserverWithHandle(globalChatHandle)
    }
    
    self.messageModels.removeAll()
    tableView.reloadData()
    
    print("LOCAL")
}

并在 viewDidDisappear 方法中替换此

ref.removeAllObservers()

ref.child("messages").removeAllObservers()