【问题标题】:How to reload UITableView without printing data twice?如何在不打印数据两次的情况下重新加载 UITableView?
【发布时间】:2016-09-13 01:56:12
【问题描述】:

我有一个作为 UITableView 工作的 SlackTextViewController 的单一视图。我正在使用公共字符串在“状态”之间切换,允许它读取某个状态下的一组数据和另一个状态下的另一组数据。问题是当我来回切换到原始状态时,它会打印数据 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{ $0.date > $1.date }
        }
        self.tableView.reloadData()
    })
}

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

    print("LOCAL")
}

【问题讨论】:

  • 您是否希望 globalChat 中的数据在您切换到 localChat 时也能保持更新?
  • 不确定这是否是问题所在,但在获取快照之前尝试使用 self.messageModel = [] 而不是 removeAll,我遇到了类似的问题,并且曾经对我有用。
  • @SamM 是的,我希望它保持更新。如果更容易停止并简单地重新加载,那就可以了。此处为中级 Swift 技能
  • @CharlesJr 你能告诉我你是如何在状态之间切换的吗?
  • @SamM 我有一个初始的公共字符串为“ALL”。单击 UINavButton 后,它会变为“本地”。基本上我只是使用几个 if 语句来读取全局信息(如果它是“ALL”)和本地信息(如果它是“本地”)。如果我需要一个结构/枚举来进行真实状态切换,请告诉我。

标签: swift uitableview firebase-realtime-database state observers


【解决方案1】:

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

由于您希望在每次切换到全局时清除聊天并加载最后 100 个,因此在切换到“本地”时保持观察者处于活动状态是没有意义的。

当您切换到本地时,只需删除观察者,这应该可以解决您的问题。


来自 firebase 文档:

- (void) removeAllObservers

移除当前引用处的所有观察者,但不移除子引用处的任何观察者。

必须为每个已建立侦听器的子引用再次调用removeAllObservers 以删除观察者。

因此,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{ $0.date > $1.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()

【讨论】:

  • 你会建议在每个聊天的顶部简单地使用 ref.removeAllObservers() 还是让每个 ref public child 包括在内并 removeAllObservers 那里?
  • ref.removeAllObservers() 只会删除该特定节点上的所有观察者。它不会删除孩子的观察者。我刚刚看到您在 viewWillDisappear 方法中使用了它,这不会删除所有内容。我将编辑我的答案以获取更多详细信息。
猜你喜欢
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 2014-05-13
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
相关资源
最近更新 更多