Firebase RTDB数据未在SwiftUI列表视图中显示

时间:2020-09-18 20:40:26

标签: swift firebase listview firebase-realtime-database swiftui

我一直在关注Internet教程,该教程将Firebase数据放入SwiftUI的列表视图中,但是该教程使用了Firestore,所以我现在一个人呆着。我拥有所有数据,但是当我打开PlayerListView时,列表为空。但是,当我打印时,所有数据都能完美打印。

这就是我所拥有的:

import SwiftUI
import Firebase

struct Player: Identifiable {
  var id: String = UUID().uuidString
  var username: String
  var score: Int
}

struct PlayerListView: View {
  @ObservedObject var viewModel = PlayerViewModel()
  @Binding var showLeaderboard: Bool

  var body: some View {
    NavigationView {
        List(viewModel.players) { player in
        VStack(alignment: .leading) {
          Text(player.username)
            .font(.headline)
          Text("\(player.score)")
            .font(.subheadline)
        }
      }
      .navigationBarTitle("Players")
        .onAppear() {
            self.viewModel.fetchData() { player in
                print(player)
            }
        }
    }
    .onTapGesture {
      self.showLeaderboard.toggle()
    }
  }
}
class PlayerViewModel: ObservableObject {
  @Published var players = [Player]()
  let ref = Database.database().reference().child("users")
    
  func fetchData(completion: @escaping(Array<Player>) -> Void) {
    ref.observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
      if let result = snapshot.children.allObjects as? [DataSnapshot] {
        for child in result {
          let orderID = child.key
          self
            .ref
            .child(orderID)
            .queryOrdered(byChild: "score")
            .observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
              let value = snapshot.value as? NSDictionary
              self.players.append(
                Player(id: .init(), 
                       username: value?["username"] as? String ?? "", 
                       score: value?["score"] as? Int ?? 0))
              completion(self.players)
            })
          }
        }
      })  
  }
}

1 个答案:

答案 0 :(得分:0)

我稍微简化了您的代码(例如,无需实现完成处理程序),并修复了一些问题。

最大的问题是您没有将玩家ID映射到id结构的Player属性。由于List要求其元素是可识别的,因此所有元素必须具有唯一的ID。但是,所有玩家都有相同的ID(一个空字符串),这导致List视图中的条目重复。

这是更新的代码:

import SwiftUI
import Firebase

struct Player: Identifiable {
  var id: String = UUID().uuidString
  var username: String
  var score: Int
}

struct PlayerListView: View {
  @ObservedObject var viewModel = PlayerViewModel()
  
  var body: some View {
    NavigationView {
      List(viewModel.players) { player in
        VStack(alignment: .leading) {
          Text(player.username)
            .font(.headline)
          Text("\(player.score)")
            .font(.subheadline)
        }
      }
      .navigationBarTitle("Players")
      .onAppear() {
        self.viewModel.fetchData()
      }
    }
  }
}
import Foundation
import Firebase

class PlayerViewModel: ObservableObject {
  @Published var players = [Player]()
  let ref = Database.database().reference().child("users")
  
  func fetchData() {
    ref.observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
      if let result = snapshot.children.allObjects as? [DataSnapshot] {
        for child in result {
          let orderID = child.key
          self
            .ref
            .child(orderID)
            .queryOrdered(byChild: "score")
            .observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
              let value = snapshot.value as? NSDictionary
              self.players.append(
                Player(id: value?["id"] as? String ?? UUID().uuidString,
                       username: value?["username"] as? String ?? "",
                       score: value?["score"] as? Int ?? 0))
            })
        }
      }
    })
  }
}

这是我的测试数据的样子:

Firebase RTDB data model

这是模拟器中UI的快照:

Snapshot of the UI