【问题标题】:Can't add data fetched from Firebase to new Array无法将从 Firebase 获取的数据添加到新数组
【发布时间】:2021-09-13 15:43:38
【问题描述】:

我正在从 3 个不同的集合中获取来自 firebase 的数据。获取数据后,我想将 3 个函数中的数据附加到 1 个新数组中,以便将所有数据存储在一个地方。但是,一旦我追加它就会变成空的,就像 fetch 函数不起作用一样。我已经测试和调试过,数据在那里,但我似乎无法将获取的数据添加到新数组中。


型号

 import Foundation
 import SwiftUI

 struct GameModel: Identifiable {
     var id = UUID()
     var title: String
     var descriptionMenu: String
     var imageNameMenu: String
 }
 

Fetch Data Class

 import Foundation
 import SwiftUI
 import Firebase

 class SearchController: ObservableObject {

     @Published var allGames = [GameModel]()

     @Published var cardsMenu = [GameModel]()
     @Published var diceMenu = [GameModel]()
     @Published var miscellaneuosMenu = [GameModel]()

     private var db = Firestore.firestore()

     func fetchCardGamesData() {...}
     func fetchDiceGamesData() {...}   
     func fetchMiscGamesData() {...}

     func combineGames() {
    
         for i in cardsMenu {
            allGames.append(i)
         }
    
         for n in diceMenu {
            allGames.append(n)
         }
    
         for x in miscellaneuosMenu {
            allGames.append(x)
         }
     }
 }

Fetch data Functions

func fetchCardGamesData() {
     db.collection("cardsMenu").addSnapshotListener { (querySnapshot, error) in
         guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
        }
        
        self.cardsMenu = documents.map { (queryDocumentSnapshot) -> GameModel in
            let data = queryDocumentSnapshot.data()
            
            let title = data["title"] as? String ?? ""
            
            let descriptionMenuRecieved = data["descriptionMenu"] as? String ?? ""
            let descriptionMenu = descriptionMenuRecieved.replacingOccurrences(of:         "\\n", with: "\n")
            
            let imageNameMenu = data["imageNameMenu"] as? String ?? ""
            
            let allGameInfo = GameModel(title: title, descriptionMenu:         descriptionMenu, imageNameMenu: imageNameMenu)
            
            return allGameInfo
        }
    }
 }

func fetchDiceGamesData() {
    db.collection("diceMenu").addSnapshotListener { (querySnapshot, error) in
        guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
        }
        
        self.diceMenu = documents.map { (queryDocumentSnapshot) -> GameModel in
            let data = queryDocumentSnapshot.data()
            
            let title = data["title"] as? String ?? ""
            
            let descriptionMenuRecieved = data["descriptionMenu"] as? String ?? ""
            let descriptionMenu = descriptionMenuRecieved.replacingOccurrences(of:     "\\n", with: "\n")
            
            let imageNameMenu = data["imageNameMenu"] as? String ?? ""
            
            let allGameInfo = GameModel(title: title, descriptionMenu:     descriptionMenu, imageNameMenu: imageNameMenu)
         
            return allGameInfo
        }
        
    }
 }

     func fetchMiscGamesData() {
    db.collection("miscellaneuosMenu").addSnapshotListener { (querySnapshot, error)     in
        guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
        }
        
        self.miscellaneuosMenu = documents.map { (queryDocumentSnapshot) ->     GameModel in
            let data = queryDocumentSnapshot.data()
            
            let title = data["title"] as? String ?? ""
            
            let descriptionMenuRecieved = data["descriptionMenu"] as? String ?? ""
            let descriptionMenu = descriptionMenuRecieved.replacingOccurrences(of:     "\\n", with: "\n")
            
            let imageNameMenu = data["imageNameMenu"] as? String ?? ""
            
            let miscellaneousGames = GameModel(title: title, descriptionMenu:     descriptionMenu, imageNameMenu: imageNameMenu)
            return miscellaneousGames
        } 
    }
 }

View
import SwiftUI
 import Foundation

 struct SearchView: View {

    @ObservedObject var allGames = SearchController()

    var body: some View {
    
        NavigationView{
            ZStack(alignment: .top) {
                GeometryReader{_ in
                    //Text("Home")
                }
                .background(Color("Color").edgesIgnoringSafeArea(.all))
            
                SearchBar(data: self.$allGames.allGames)
                    .padding(.top)
            }
            .navigationBarTitle("Search")
            .padding(.top, -20)
            .onAppear(){
                self.allGames.fetchCardGamesData()
                self.allGames.fetchDiceGamesData()
                self.allGames.fetchMiscGamesData()
                self.allGames.combineGames()
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
        .listStyle(PlainListStyle())
    }
 }

搜索栏

struct SearchBar: View {

@State var txt = ""
@Binding var data: [GameModel]

var body: some View {
    
    VStack(spacing: 0){
        
        HStack{
            
            TextField("Search", text: self.$txt)
            
            if self.txt != "" {
                
                Button(action: {
                    
                    self.txt = ""
                    
                }, label: {
                    Image(systemName: "xmark.circle.fill")
                })
                .foregroundColor(.gray)
            }
        }.padding()
        
        if self.txt != ""{
            
            if self.data.filter({$0.title.lowercased().contains(self.txt.lowercased())}).count == 0 {
                Text("No Results Found")
                    .foregroundColor(Color.black.opacity(0.5))
                    .padding()
            }
            else {
                
                List(self.data.filter{$0.title.lowercased().contains(self.txt.lowercased())}){
                    i in
                    
                    NavigationLink(destination: i.view.navigationBarTitleDisplayMode(.inline).onAppear(){
                        // Clear searchfield when return
                        txt = ""
                    }) {
                        Text(i.title)
                    }
                }
                .frame(height: UIScreen.main.bounds.height / 3)
                .padding(.trailing)
            }
        }
    }
    .background(Color.white)
    .cornerRadius(10)
    .padding()
}

}

希望你们能帮助我。

【问题讨论】:

    标签: swift firebase google-cloud-firestore swiftui


    【解决方案1】:

    您的所有fetchCardGamesDatafetchDiceGamesDatafetchMiscGamesData 函数都包含异步请求。这意味着当你调用combineGames 时,它们都没有完成,所以你只是在追加空数组。

    在您的情况下,最简单的方法可能是将allGames 设为计算属性。然后,每当其他@Published 属性之一在其fetch 方法之后更新时,计算的属性将被重新计算并在您的SearchBar 中表示:

    class SearchController: ObservableObject {
        
        @Published var cardsMenu = [GameModel]()
        @Published var diceMenu = [GameModel]()
        @Published var miscellaneuosMenu = [GameModel]()
        
        var allGames: [GameModel] {
            cardsMenu + diceMenu + miscellaneuosMenu
        }
    }
    

    请注意,不再有 combineGames 函数,因此您不会再调用它了。

    【讨论】:

    • 我已添加计算属性,但在 SearchView 中出现错误“无法分配给属性:'allGames' 是仅获取属性”。如何从 SearchController 获取数据到 SeachView 以到达 SearchBar
    • 由于您没有包含SearchBar,我没有意识到它需要对allGames 的写入权限。通常在搜索栏中,您根据搜索条件过滤数据。也许这就是你应该做的?如果没有,我可以提供不同的解决方案,但是根据正在搜索的内容来改变 allGames 似乎很有趣......
    • 对不起,我忘了。我现在在帖子中添加了 SearchBar。
    • 你永远不会变异data。只需删除声明前的@Binding,不要在调用现场使用$SearchBar(data: self.allGames.allGames)
    • 好吧,我很想看到你接受。我对 Swift 和 SwitUI 还很陌生,所以我还在边学习边学习。
    猜你喜欢
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 2020-09-12
    相关资源
    最近更新 更多