Firebase生成的数据表无法稳定显示

Posted

技术标签:

【中文标题】Firebase生成的数据表无法稳定显示【英文标题】:Data table generated from Firebase cannot be displayed stably 【发布时间】:2021-04-29 16:40:37 【问题描述】:

我需要开发一个具有排行榜功能的移动应用。排行榜只显示在一个选项卡上,但是,每次我从另一个选项卡返回此页面时,排行榜总是立即消失(请看这个screen record)。有没有办法让数据稳定显示?

这是我的代码 sn-p:

// LeaderboardView.swift

import SwiftUI

struct Leaderboard: View 
    @ObservedObject private var users = UserViewModel()
    var body: some View 
// ...
            NavigationView 
                List(users.topFiveUsers) 
                    user in
                    VStack 
                        HStack 
                            Text(verbatim: user.name).font(.headline)
                            Text(verbatim: String(user.xp)).font(.subheadline)
                        
                    
                
            
            .navigationTitle(Text("Leaderboard"))
            Spacer()
        
        .background(Color.white)
    


struct Leaderboard_Previews: PreviewProvider 
    static var previews: some View 
        Leaderboard()
    

// UserViewModel.swift

import Foundation
import Firebase
import FirebaseFirestore

class UserViewModel: ObservableObject 
    @Published var topFiveUsers = [User]()
    private var db = Firestore.firestore().collection("Users")
        
    public init() 
        let top5 = db.order(by: "xp", descending: true).limit(to: 5)
        top5.addSnapshotListener  (QuerySnapshot, error) in
            guard let documents = QuerySnapshot?.documents else 
                print("Document is empty")
                return
            
            self.topFiveUsers = documents.map 
                (QueryDocumentSnapshot) -> User in
                let data = QueryDocumentSnapshot.data()
                let xp = data["xp"]
                let name = data["username"]
                return User(name:name as? String ?? "", xp:xp as? Int ?? 0)
            
        
    

// User.swift

import SwiftUI
import Firebase

class User : ObservableObject, Identifiable 
    @Published var name = ""
    @Published var bio = ""
    @Published var interest = ""
    @Published var level = 1
    @Published var xp = 0
    @Published var email = ""
    @Published var image_Data = Data(count: 0)
    @Published var picker = false
    
    let ref = Firestore.firestore()
    
    @Published var isLoading = false
    @AppStorage("status") var status = false
    
    // common init
    init() 
        
    
    
    //initializer for leaderboard collection
    init(name: String, xp: Int) 
        self.name = name
        self.xp = xp
        self.level = User.xp2Level(xp: xp)
    

// ContentView.swift

struct ContentView: View 
    init() 
        UITabBar.appearance().isHidden = true
    
    @State var centerX : CGFloat = 0
    @State var goToHome = false
    @State var edge = UIApplication.shared.windows.first?.safeAreaInsets
//    @Environement(.verticalSizeClass) var size
    var body: some View 
        
        ZStack 
            if goToHome 
                
                NavigationView 
                    CustomTabView(centerX: $centerX)
                        .navigationBarTitleDisplayMode(.inline)
                        .navigationBarHidden(true)
                
            
            else 
                OnBoardScreen()
            
        
        .onReceive(NotificationCenter.default.publisher(for:Notification.Name("Success")), perform: 
            _ in withAnimationself.goToHome = true
        )
    
        


struct CustomTabView : View 
    //swich tabs
    @State var selectedTab = "home"
    @Binding var centerX : CGFloat
    var body : some View 
        
        ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom))
            TabView(selection: $selectedTab) 
                Home()
                    .tag("home")
                Leaderboard()
                    .tag("Leaderboard")
                Pal()
                    .tag("profile")
            
//            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .ignoresSafeArea(.all, edges: .all)
            
//            Spacer()
            HStack(spacing: 0) 
                ForEach(tabs, id: \.self) image in
                    GeometryReader reader in
                        TabButton(image: image, centerX: $centerX, rect:reader.frame(in:.global), selectedTab: $selectedTab)
                        //setting initial curve
                            .onAppear(perform: 
                                if image == tabs.first
                                    centerX = reader.frame(in: .global).midX
                                
                            )
                    
                    .frame(width: 50, height: 30)
                    if image != tabs.last Spacer(minLength: 0)
                
            
            .padding(.horizontal, 30)
//            .padding(.top)
            .padding(.vertical, 17)
            .padding(.bottom, 20)
            .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom == 0 ? 15: 0)
            .background(Color("5324FF").clipShape(AnimatedShape(centerX: centerX)))
            .shadow(color: Color.blue.opacity(0.1), radius: 5, x: 0, y: -5)
//            .ignoresSafeArea(.all, edges: .all)
        
        .ignoresSafeArea(.all, edges: .all)
           
    

【问题讨论】:

这个问题与您处理显示视图的方式有关。用户对象、firebase 和排行榜本身的代码与问题无关。请发布代码,显示您如何显示不同的标签项。 感谢您的建议,我已经编辑了我的问题。请参考。 同意 xTwisteDx 所说的 - 问题在于您如何处理选项卡视图的选定状态。我建议将其设置在一个较小的复制案例中,这样您就不会被所有其他代码分心。另外,请不要手动映射 Firestore 数据 - 改用 Codable。我为此写了一份综合指南:peterfriese.dev/firestore-codable-the-comprehensive-guide。此外,请确保将 Firestore 文档 ID 与用户的 id 属性进行映射,以使其真正可识别。 【参考方案1】:

即使@State 有效,您也应该使用@StateObject。如果使用@State,SwiftUI 可能会随机销毁 Object。

@StateObject private var users = UserViewModel()

【讨论】:

【参考方案2】:

我将视图文件中变量users 的属性从ObservedObject 更改为State。然后桌子就稳定了。

【讨论】:

以上是关于Firebase生成的数据表无法稳定显示的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Firebase 中的第二个生成的密钥获取数据?

无法从 Firebase 将数据显示为 ListView

HashMap 为空,因此我无法从 Firebase 数据库获取模拟器中显示的数据

无法显示从Firebase提取的数据到reactjs Webapp中

本地写入是不是以与生成的顺序相同的顺序提交到 firebase

我想从firebase实时数据库中显示recyclerview android上的数据..但我无法将动态数据加载到适配器数组中