使用数组中的新信息更新该对象并显示 tableview Swift

Posted

技术标签:

【中文标题】使用数组中的新信息更新该对象并显示 tableview Swift【英文标题】:Update that object with the new info in array and to display tableview Swift 【发布时间】:2019-10-30 10:51:25 【问题描述】:

我正在使用 firebase 实时数据库并使用 usersFriend 和位置实现用户配置文件数据。我需要在对象数组中实现更新并在表格视图中显示更新的值。我已经尝试过,但我没有成功更新对象,然后重新加载 tableview。功能已开发。

我需要显示用新值交换的更新对象数组并显示在表格视图中。

var myFriendsDataSource = [FriendClass]()

func watchForChangesInMyFriends()  
  let usersRef = self.ref.child("profiles") usersRef.observe(.childChanged, with:  snapshot in 
    let key = snapshot.key 
    if let friendIndex = self.myFriendsDataSource.firstIndex(where:  $0.uid == key )  
      let friend = self.myFriendsDataSource[friendIndex] 
      print("found user \(friend.batteryStatus), updating")
      self.myFriendsDataSource[friendIndex] = friend 
      self.tableView.reloadData() 
     
  ) 

类:

class FriendClass 

    var uid = ""
    var name = ""
    var batteryStatus = Int()
    var latitude = Double()
    var longitude = Double()
    var timeStamp = Int64()

    //var profilePic

    init(withSnapshot: DataSnapshot) 

        self.uid = withSnapshot.key
        self.name = withSnapshot.childSnapshot(forPath: "name").value as? String ?? "No Name"
        self.batteryStatus = withSnapshot.childSnapshot(forPath: "batteryStatus").value as? Int ?? 0
        self.latitude = withSnapshot.childSnapshot(forPath: "latitude").value as? Double ?? 0.0
        self.longitude = withSnapshot.childSnapshot(forPath: "longitude").value as? Double ?? 0.0
        self.timeStamp = withSnapshot.childSnapshot(forPath: "timeStamp").value as? Int64  ?? 0

    

更新:

func loadUsersFriends() 

let uid = "zzV6DQSXUyUkPHgENDbZ9EjXVBj2"
let myFriendsRef = self.ref.child("userFriends").child(uid)
myFriendsRef.observeSingleEvent(of: .value, with:  snapshot in
let uidArray = snapshot.children.allObjects as! [DataSnapshot]
   for friendsUid in uidArray 
          self.loadFriend(withUid: friendsUid.key)
          print(friendsUid)
         
     )
 

func loadFriend(withUid: String) 
  let thisUserRef = self.ref.child("profiles").child(withUid)
  thisUserRef.observeSingleEvent(of: .value, with:  snapshot in
  let aFriend = FriendClass(withSnapshot: snapshot)
  self.myFriendsDataSource.append(aFriend)
  print(self.myFriendsDataSource)
  self.tableView.reloadData()
  self.watchForChangesInMyFriends()

        )
    

更新 2:

extension ViewController: UITableViewDelegate 
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 70
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
        return 10
    


extension ViewController: UITableViewDataSource 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return myFriendsDataSource.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "FriendListTableViewCell", for: indexPath) as! FriendListTableViewCell
        let dic = myFriendsDataSource[indexPath.row]

        cell.frndName.text = dic.name

        return cell
    

【问题讨论】:

如果没有看到您的 tableView 代码,就无法告知为什么 tableView 没有正确重新加载。但是,您的 watchFor... 函数中似乎存在逻辑错误:您得到 friendIndex,在该索引处设置 friend = 值,然后在不更改朋友的情况下,将该索引处的值设置回 friend。基本上你设置的东西等于它自己。您的意思是在将 friend 放回数组之前更新它吗? @flanker 我更新了我的问题并添加了两个主要功能,即loadFriendloadUsersFriends。关于friend 包含模型中需要更改的匹配值。我需要从快照中读取信息,使用数组中的新信息更新该对象,然后重新加载 tableView。 watchFor... 已有新快照。 如果我没看错的话,watchFor... 方法会注册一个闭包,只要底层的 firebase 数据发生变化就会被调用,当闭包被调用时,它会提供该变化的快照,并且那么你想用新数据更新你的myFriendsDataSource 数组吗?正确的?目前您正在查找friend 的数组元素,将其打印出来,但实际上并未使用快照中的新数据对其进行更新?因此,假设tableView 数据源是myFriendsDataSource 数组,则tableView 中不会有任何更新 @flanker 是的,你的分析是正确的。 @flanker 是正确的。你正在做这个let friend = self.myFriendsDataSource[friendIndex],然后从数组中取出那个朋友,然后用这个self.myFriendsDataSource[friendIndex] = friend把它放回去,而你想做的是self.myFriendsDataSource[friendIndex] = data from snapshot 【参考方案1】:

鉴于上述评论讨论,我认为您需要如下更新您的watchForChangesInMyFriends 方法,以便使用新朋友数据实际更新数据源。您还应该在主线程上进行所有 UI 更新,并且由于无法保证此闭包将在主线程上运行,因此您需要将 tableView 更新强制到主线程上。

func watchForChangesInMyFriends()  
  let usersRef = self.ref.child("profiles") usersRef.observe(.childChanged, with:  snapshot in 
    let key = snapshot.key 
    if let friendIndex = self.myFriendsDataSource.firstIndex(where:  $0.uid == key )  
      let friend = self.myFriendsDataSource[friendIndex] 
      print("found user \(friend.batteryStatus), updating")
      self.myFriendsDataSource[friendIndex] = FriendClass(withSnaphot: snapshot)
      DispatchQueue.main.async 
        self.tableView.reloadData()
       
     
  ) 

最好只更新已更改的 tableView 数据,而不是重新加载整个 tableView。您可能可以使用数组索引为适当的行生成IndexPath,然后重新加载该行。如果没有看到您的 tableView 方法,我无法准确,但它可能看起来像这样:

let indexPath = IndexPath(row: friendIndex, section: 0)
DispatchQueue.main.async 
  self.tableView.reloadRows(at: [indexPath], with: .automatic)

【讨论】:

感谢您与 self.tableView.reloadData() 完美配合。但是对于tableView.reloadRows 它不起作用。我已经用我的 tableview 方法更新了问题。 在 reloadRows 之前也需要self.。如果失败,分享错误信息 我在 Xcode 中出现红色警告之前使用了self.。但现在我再次尝试了它的工作。两种方式都成功。完美,非常感谢。 :) @Newbie 这在 Firebase 闭包中不需要 DispatchQueue.main.async 。 Firebase 闭包中的所有 UI 调用都在主线程上完成。请参阅来自 Firebaser 的 this answer 了解更多信息。 谢谢@Jay。我从未使用过 Firebase,只是将其视为标准闭包,但很高兴向那些拥有的人让步:)

以上是关于使用数组中的新信息更新该对象并显示 tableview Swift的主要内容,如果未能解决你的问题,请参考以下文章

将数组保存并更新到本地存储JS

JS 遍历对象数组并将值更改为匹配的键并创建一个包含对象数组 [0] 中的键的新对象

如何从对象数组中获取特定数据并存储在js(vue js)中的新数组中

如何显示数组中的刷新值

Mongo 文档中的更新数组不起作用

原型中的数组和对象 - 不被视为引用