Swiftui 附加到结构数组不起作用

Swiftui append to a struct array doesn't work

我正在学习swiftui。但是现在我遇到了一个问题。 我正在尝试将数据附加到结构数组。

struct outfit:Identifiable {
var id = UUID()
var user: String
var amount: Double
var rating: Double
}

和另一个文件

import SwiftUI
import Firebase
import FirebaseStorage
import FirebaseFirestore

struct rate: View {
private var db = Firestore.firestore()
@State var user = Auth.auth().currentUser
@State private var outfitcards = [outfit]()
@State private var cards = [1, 2, 3]
@State private var offset = [CGSize.zero, CGSize.zero]

init () {
    loadcards()
}

var body: some View {
    GeometryReader { frame in
        ZStack{
            VStack {
                Text("outfit")
                    .font(.largeTitle)
                    .padding()
                
                ZStack {
                    Text("No cards to show")
                        .frame(width: frame.size.width * 0.6, height: frame.size.width * 1.6)
                    
                    HStack {
                        Image(systemName: "record.circle.fill")
                            .foregroundColor(.red)
                        Spacer()
                        Image(systemName: "record.circle.fill")
                            .foregroundColor(.green)

                        
                    }
                    
    
                    ForEach(outfitcards) { index in
                        Text(index.user)
                    }
                }
            }
        }
    }
}
func loadcards () {
    db.collection("rating").whereField("user", isNotEqualTo: user?.uid ?? "Error")
        .getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err.localizedDescription)")
            } else {
                for document in querySnapshot!.documents {
                   let cuser = document.get("user") as! String
                    let camount = document.get("amount") as! Double
                   let crating = document.get("rating") as! Double
                    print("user=\(cuser) amount=\(camount) crating=\(crating)")
                    outfitcards.append(outfit(user: cuser, amount: camount, rating: crating))
                }
                print(outfitcards)
            }
         }
    }
}

它确实打印了用户名、金额和评级,但是当我打印数组本身时,它给了我一个 []。所以它不追加。另外 for each 循环是空的,所以这也意味着数组是空的

没有附加任何内容

有人知道我做错了什么吗?

像这样在 View 中加载数据是一种危险的做法,只要重新呈现视图(甚至在这种情况下甚至重新启动),它就会得到 reset/reloaded。

相反,将加载数据的代码移动到 ObservableObject:


struct Outfit:Identifiable {
    var id = UUID()
    var user: String
    var amount: Double
    var rating: Double
}

class Loader : ObservableObject {
    private var db = Firestore.firestore()
    private var user = Auth.auth().currentUser
    @Published var outfitcards = [Outfit]()
    
    func loadcards () {
        db.collection("rating").whereField("user", isNotEqualTo: user?.uid ?? "Error")
            .getDocuments() { (querySnapshot, err) in
                if let err = err {
                    print("Error getting documents: \(err.localizedDescription)")
                } else {
                    for document in querySnapshot!.documents {
                        let cuser = document.get("user") as! String
                        let camount = document.get("amount") as! Double
                        let crating = document.get("rating") as! Double
                        print("user=\(cuser) amount=\(camount) crating=\(crating)")
                        self.outfitcards.append(Outfit(user: cuser, amount: camount, rating: crating))
                    }
                    print(self.outfitcards)
                }
            }
    }
}

struct Rate: View {
    @StateObject var loader = Loader()
    @State private var cards = [1, 2, 3]
    @State private var offset = [CGSize.zero, CGSize.zero]
    
    var body: some View {
        GeometryReader { frame in
            ZStack{
                VStack {
                    Text("outfit")
                        .font(.largeTitle)
                        .padding()
                    ZStack {
                        Text("No cards to show")
                            .frame(width: frame.size.width * 0.6, height: frame.size.width * 1.6)
                        
                        HStack {
                            Image(systemName: "record.circle.fill")
                                .foregroundColor(.red)
                            Spacer()
                            Image(systemName: "record.circle.fill")
                                .foregroundColor(.green)
                        }
                        ForEach(loader.outfitcards) { index in
                            Text(index.user)
                        }
                    }
                }
            }
        }.onAppear {
            loader.loadcards()
        }
    }
}

现在,加载程序负责进行数据库调用。它更新视图观察到的@Published 属性。

请注意,我更改了一些东西(Rate、Outfit)的大写。在Swift中,通常的做法是类型大写(classes/structs/enums),变量名以小写字母开头。

还可能值得注意的是,您从 firebase(使用 as!)转换数据的方式很危险,如果数据不是您期望的格式,可能会使您的程序崩溃。最好使用可选绑定 (let user = document.get("user") as? String)

您的问题是您在初始化视图时更新了@State 值,这是您以错误的方式进行的,在出现时这样做:

    struct rate: View {
private var db = Firestore.firestore()
@State var user = Auth.auth().currentUser
@State private var outfitcards = [outfit]()
@State private var cards = [1, 2, 3]
@State private var offset = [CGSize.zero, CGSize.zero]


var body: some View {
    GeometryReader { frame in
        ZStack{
            VStack {
                Text("outfit")
                    .font(.largeTitle)
                    .padding()
                
                ZStack {
                    Text("No cards to show")
                        .frame(width: frame.size.width * 0.6, height: frame.size.width * 1.6)
                    
                    HStack {
                        Image(systemName: "record.circle.fill")
                            .foregroundColor(.red)
                        Spacer()
                        Image(systemName: "record.circle.fill")
                            .foregroundColor(.green)

                        
                    }
                    
    
                    ForEach(outfitcards) { index in
                        Text(index.user)
                    }
                }
            }
        }
    }
    .onAppear() { loadcards() }  // <<: Here
}
func loadcards () {
    db.collection("rating").whereField("user", isNotEqualTo: user?.uid ?? "Error")
        .getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err.localizedDescription)")
            } else {
                for document in querySnapshot!.documents {
                   let cuser = document.get("user") as! String
                    let camount = document.get("amount") as! Double
                   let crating = document.get("rating") as! Double
                    print("user=\(cuser) amount=\(camount) crating=\(crating)")
                    outfitcards.append(outfit(user: cuser, amount: camount, rating: crating))
                }
                print(outfitcards)
            }
         }
    }
}