I built an MVVM architecture to support my app which is supposed to control the pipeline between the frontend and my firebase database. Initially, I successfully implemented the entire work by coding totally in the frontend, but there are lots of bugs when I encapsulated them into a function.
For example, the next sheet will be presented when the currently presented sheet gets dismissed. Sometimes I needed to wait for a long time until the app is unfrozen. Even worse, the app crashed down when I clicked the button.
I heard that nested models don't work yet if SwiftUI is in use (reference). However, I just cannot come up with a better solution if my classes are untested.
// This is Model
import Foundation
import SwiftUI
struct userModel {
    var uid = UUID()
    var name = ""
    var bio = ""
    var interest = ""
    var level = 1
    var xp = 0
    var email = ""
    var image: Data = Data(count: 0)
    
    init() {
        
    }
    
    init(_ name:String, _ xp: Int) {
        self.name = name
        self.xp = xp
        self.level = self.xp2Level(xp: xp)
    }
    
    func xp2Level(xp:Int) -> Int {
        if xp < 9500 {
            return xp / 500 + 1
        }
        else if xp < 29500 {
            return (xp - 9500) / 1000 + 1
        }
        else {
            return (xp - 29500) / 2000 + 1
        }
    }
}
// This is ViewModel
import Foundation
import SwiftUI
import Firebase
class userViewModel: ObservableObject {
    @Published var user: userModel = userModel()
    
    @Published var isLoading = false
    @AppStorage("status") var status = false
    private var ref = Firestore.firestore()
    private let store = Storage.storage().reference()
    var picker = false
    
    func updateXP(completion: @escaping () -> Int) -> Int {
        guard let uid = Auth.auth().currentUser?.uid else {
            return 0
        }
        // catch the information of the current user
        let db = ref.collection("Users")
        db.addSnapshotListener { [self] (querySnapshot, error) in
            guard (querySnapshot?.documents) != nil else {
                print("Document is empty")
                return
            }
            let docRef = db.document(uid)
            
            docRef.getDocument { (snapshot, error) in
                if let doc = snapshot,
                   let xp = doc.get("xp") as? Int {
                    self.user.xp = xp
                }
            }
        }
        return completion()
    }
    
    func updateLevel(completion: @escaping () -> Int) -> Int {
        guard let uid = Auth.auth().currentUser?.uid else {
            return 1
        }
        // catch the information of the current user
        let db = ref.collection("Users")
        db.addSnapshotListener { [self] (querySnapshot, error) in
            guard (querySnapshot?.documents) != nil else {
                print("Document is empty")
                return
            }
            let docRef = db.document(uid)
            
            docRef.getDocument { (snapshot, error) in
                if let doc = snapshot,
                   let level = doc.get("level") as? Int {
                    self.user.level = level
                }
            }
        }
        return completion()
    }
    
    func updateName (completion: @escaping () -> String) -> String {
        guard let uid = Auth.auth().currentUser?.uid else {
            return ""
        }
        // catch the information of the current user
        let db = ref.collection("Users")
        db.addSnapshotListener { [self] (querySnapshot, error) in
            guard (querySnapshot?.documents) != nil else {
                print("Document is empty")
                return
            }
            let docRef = db.document(uid)
            
            docRef.getDocument { (snapshot, error) in
                if let doc = snapshot,
                   let name = doc.get("username") as? String {
                    self.user.name = name
                }
            }
        }
        return completion()
    }
    
    func updateBio (completion: @escaping () -> String) -> String {
        guard let uid = Auth.auth().currentUser?.uid else {
            return ""
        }
        // catch the information of the current user
        let db = ref.collection("Users")
        db.addSnapshotListener { [self] (querySnapshot, error) in
            guard (querySnapshot?.documents) != nil else {
                print("Document is empty")
                return
            }
            let docRef = db.document(uid)
            
            docRef.getDocument { (snapshot, error) in
                if let doc = snapshot,
                   let bio = doc.get("bio") as? String {
                    self.user.bio = bio
                }
            }
        }
        return completion()
    }
    
    func updateInterest (completion: @escaping () -> String) -> String {
        guard let uid = Auth.auth().currentUser?.uid else {
            return ""
        }
        // catch the information of the current user
        let db = ref.collection("Users")
        db.addSnapshotListener { [self] (querySnapshot, error) in
            guard (querySnapshot?.documents) != nil else {
                print("Document is empty")
                return
            }
            let docRef = db.document(uid)
            
            docRef.getDocument { (snapshot, error) in
                if let doc = snapshot,
                   let interest = doc.get("interest") as? String {
                    self.user.interest = interest
                }
            }
        }
        return completion()
    }
    
    func updatePhoto (completion: @escaping () -> Data) -> Data {
        guard let uid = Auth.auth().currentUser?.uid else {
            return Data(count: 0)
        }
        
        // catch the information of the current user
        let db = ref.collection("Users")
        db.addSnapshotListener { [self] (querySnapshot, error) in
            guard (querySnapshot?.documents) != nil else {
                print("Document is empty")
                return
            }
            let docRef = db.document(uid)
            
            docRef.getDocument { (snapshot, error) in
                if snapshot != nil {
                    let imageRef = store.child("profile_Photos").child(uid)
                    imageRef.getData(maxSize: 1000 * 64 * 64, completion: { (data, error) in
                        if let error = error {
                            print("Encountered error: \(error) when getting image")
                            self.user.image = Data(count: 0)
                        } else if let data = data,
                                  !data.isEmpty{
//                            self.currentUser.image = Image(uiImage: UIImage(data: data)!).resizable()
                            self.user.image = data
                        } else {
//                            self.currentUser.image = Image(systemName: "person").resizable()
                            self.user.image = Data(count: 0)
                        }
                      })
                } else if let error = error {
                    print(error)
                }
            }
        }
        return completion()
    }
    
    public func getXP() -> Int{
        updateXP {
            return (self.user.xp) as Int
        }
    }
    
    public func getLevel() -> Int {
        updateLevel(completion: {
            return (self.user.level) as Int
        })
    }
    
    public func getName() -> String {
        updateName(completion: {
            return (self.user.name) as String
        })
    }
    
    public func getBio() -> String {
        updateBio(completion: {
            return (self.user.bio) as String
        })
    }
    
    public func getInterest() -> String {
        updateInterest(completion: {
            return (self.user.interest) as String
        })
    }
    
    public func getPhoto() -> Data {
        updatePhoto(completion: {
            return (self.user.image) as Data
        })
    }
    
    func updatePersonalInfo() {
        //sending user data to Firebase
        let uid = Auth.auth().currentUser?.uid
        
        isLoading = true
        self.uploadImage(imageData: self.getPhoto(), path: "profile_Photos") { (url) in
            self.ref.collection("Users").document(uid ?? "").setData([
                            "uid": uid ?? "",
                            "imageurl": url,
                            "username": self.user.name,
                            "bio": self.user.bio,
                            "interest" : self.user.interest
                        ], merge: true) { (err) in
                         
                            if err != nil{
                                self.isLoading = false
                                return
                            }
                            self.isLoading = false
                            // success means settings status as true...
                            self.status = true
                        }
            
        }
    }
    
    func increaseXPnLV() {
        //sending user data to Firebase
        let uid = Auth.auth().currentUser!.uid
        let docRef = ref.collection("Users").document(uid)
        docRef.getDocument { (document, error) in
            if let document = document, document.exists {
                docRef.updateData(["xp": FieldValue.increment(Int64(50))])
                // update level
                let xp = document.data()!["xp"] as! Int
                docRef.updateData(["level": self.user.xp2Level(xp: xp)])
            } else {
                print("Document does not exist")
            }
        }
    }
    
    func uploadImage(imageData: Data, path: String, completion: @escaping (String) -> ()){
        
        let storage = Storage.storage().reference()
        let uid = Auth.auth().currentUser?.uid
        
        storage.child(path).child(uid ?? "").putData(imageData, metadata: nil) { (_, err) in
            print("imageData: \(imageData)")
            if err != nil{
                completion("")
                return
                
            }
            // Downloading Url And Sending Back...
            storage.child(path).child(uid ?? "").downloadURL { (url, err) in
                if err != nil{
                    completion("")
                    return
                    
                }
                completion("\(url!)")
            }
        }
    }
}
// This is View
import SwiftUI
import CoreData
import Firebase
import FirebaseFirestore
struct Goals: View {
    let current_user_id = Auth.auth().currentUser?.uid
    @State private var showingAlert = false
    var ref = Firestore.firestore()
    @StateObject var currentUser: userViewModel
    @StateObject var homeData = HomeViewModel()
    @State var txt = ""
    @State var edge = UIApplication.shared.windows.first?.safeAreaInsets
    @FetchRequest(entity: Goal.entity(), sortDescriptors: [NSSortDescriptor(key: "date",
                                                                            ascending: true)], animation: .spring()) var results : FetchedResults<Goal>
    
//    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    @State private var greeting : String = "Hello"
    @Environment(\.managedObjectContext) var context
    var body: some View {
    ForEach(results){goal in
    Button(action: {
                                            context.delete(goal)
                                            try! context.save()
                                            if current_user_id != nil {
                                                currentUser.updateXPnLV()
                                                self.showingAlert = true
                                            }
                                        }, label: Text("Something")
    )
                                            .alert(isPresented: $showingAlert) {
                                        () -> Alert in
                                        Alert(title: Text("Congratulations!"), message: Text("You completed a goal today, XP+50!"), dismissButton: .default(Text("OK")))
                                            }
    }
}
}
EDIT
Another error I saw is AttributeGraph precondition failure: attribute failed to set an initial value: 805912, ForEachChild<Array<userInfoModel>, ObjectIdentifier, HStack<VStack<HStack<TupleView<(Text, Divider, Text)>>>>>.
 
    