Swift 使用MVVM嵌套模型更新存储在Firebase中的数据

Swift 使用MVVM嵌套模型更新存储在Firebase中的数据,swift,firebase,mvvm,swiftui,nested,Swift,Firebase,Mvvm,Swiftui,Nested,我构建了一个MVVM架构来支持我的应用程序,该应用程序应该控制前端和firebase数据库之间的管道。最初,我通过完全在前端编码成功地实现了整个工作,但是当我将它们封装到函数中时,有很多bug 例如,当前提交的工作表被驳回时,将提交下一个工作表。有时我需要等待很长时间,直到应用程序解冻。更糟糕的是,当我点击按钮时,应用程序崩溃了 我听说如果使用SwiftUI(),嵌套模型还不能工作。然而,如果我的类未经测试,我就无法找到更好的解决方案 // This is Model import Founda

我构建了一个MVVM架构来支持我的应用程序,该应用程序应该控制前端和firebase数据库之间的管道。最初,我通过完全在前端编码成功地实现了整个工作,但是当我将它们封装到函数中时,有很多bug

例如,当前提交的工作表被驳回时,将提交下一个工作表。有时我需要等待很长时间,直到应用程序解冻。更糟糕的是,当我点击按钮时,应用程序崩溃了

我听说如果使用SwiftUI(),嵌套模型还不能工作。然而,如果我的类未经测试,我就无法找到更好的解决方案

// 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
        }
    }
}
//这是视图
导入快捷键
导入CoreData
进口火基
导入FirebaseFirestore
结构目标:视图{
让current_user_id=Auth.Auth().currentUser?.uid
@国家私有变量showingAlert=false
var ref=Firestore.Firestore()
@StateObject变量currentUser:userViewModel
@StateObject变量homeData=HomeViewModel()
@State var txt=“”
@State var edge=UIApplication.shared.windows.first?.safeAreaInsets
@FetchRequest(实体:Goal.entity(),SortDescriptor:[NSSortDescriptor(键:“日期”,
升序:true)],动画:.spring())变量结果:FetchedResults
//让timer=timer.publish(每隔:1,在:.main上,在:.common中)。自动连接()
@状态私有变量问候语:String=“Hello”
@环境(\.managedObjectContext)变量上下文
var body:一些观点{
ForEach(results){goal in
按钮(操作:{
删除(目标)
试试!context.save()
如果当前用户id!=nil{
currentUser.updatepnlv()
self.showinglert=true
}
},标签:文本(“某物”)
)
.警报(显示:$showingAlert){
()->警报进入
警报(标题:文本(“恭喜!”),消息:文本(“您今天完成了一个目标,XP+50!”),解雇按钮:。默认值(文本(“确定”))
}
}
}
}
编辑

我看到的另一个错误是
AttributeGraph前置条件失败:attribute未能设置初始值:805912,ForEachChild。

  • AppStorage
    用于
    视图
    中,而它可能会在
    视图的
    结构
    之外的
    可观察对象
    中运行所有SwiftUI包装,但
    @已发布的
    除外
  • 作为标准做法,所有的
    结构
    都应该大写,因此更改
    类CurrentUserViewModel
    类UserInfoModel
  • 另外,将
    @StateObject var currentUser:currentUserViewModel
    更改为
    @StateObject var currentUser:currentUserViewModel=currentUserViewModel()

    初始化是缺少的最重要的部分

  • ForEach
    中的所有内容都是浮动的,它不在变量、函数或
    正文中。你的
    身体在哪里
  • 这可能就是错误所说的。将所有代码包装在一个正文中

    var body: some View {
        //All the code for the ForEach
    }
    
  • 您的
    按钮
    似乎缺少
    标题
    标签

  • 删除此行

    ()->中的警报

  • 我相信还有其他的小事情。我建议您在这个
    视图中从头开始
    ,然后开始逐行输入代码

    这是一个起点。Firebase部分需要大量的工作,但您应该能够通过关注我注释掉的代码并删除代码来模拟Firebase的响应来开始

    所有这些都在FirebaseManager类中

    一旦这起作用,其余的都会起作用

    代码按原样工作,这样您就可以看到它与假响应一起工作

    ///Keep all the Firebase Code HERE
    class FirebaseManager{
        //private var ref = Firestore.firestore()
        //private let store = Storage.storage().reference()
        func retrieveFromDB(collectionName: String, variableName: String, completion:  @escaping (Result<Any, Error>) -> Void) {
            print(#function)
            //This is sample code, likely has errors because I dont have Firebase setup but you can see the logic so you can touch up
            
            //        guard let uid = Auth.auth().currentUser?.uid else {
            //            completion(.failure(FirebaseError.notLoggedIn))
            //            return
            //        }
            // catch the information of the current user
            //        let db = ref.collection(collectionName)
            //        db.addSnapshotListener { [self] (querySnapshot, error) in
            //
            //            if let error = error{
            //                completion(.failure(error))
            //                return
            //            }
            //            guard (querySnapshot?.documents) != nil else {
            //                print("Document is empty")
            //                completion(.failure(FirebaseError.emptyDocument))
            //                return
            //            }
            //            let docRef = db.(document(uid)
            //
            //            docRef.getDocument { (snapshot, error) in
            //                if let error = error{
            //                    completion(.failure(error))
            //                    return
            //                }
            //
            //            completion(.success(snapshot.get(variableName)))
            //            }
            //        }
            //For sample purposes I will mimic response remove this in your actual code
            DispatchQueue.main.async {
                if variableName == "xp" || variableName == "level"{
                    completion(.success(Int.random(in: 0...200)))
                }else{
                    let strings = ["apple", "orange", "banana", "kiwi", "startfruit"]
                    completion(.success(strings.randomElement()!))
                }
            }
        }
        ///For Int variables
        func retrieveFromUsers(variableName: String, completion: @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            retrieveFromDB(collectionName: "Users", variableName: variableName, completion: {result in
                switch result {
                case .success(let value):
                    let xp = value as? Int
                    if xp != nil{
                        completion(.success(xp!))
                    }else{
                        completion(.failure(FirebaseError.wrongType))
                    }
                    return
                case .failure(let error):
                    print(error)
                    completion(.failure(error))
                }
            })
        }
        ///For String variables
        func retrieveUserProperty(variableName: String, completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveFromDB(collectionName: "Users", variableName: variableName, completion: {result in
                switch result {
                case .success(let value):
                    let username = value as? String
                    if username != nil{
                        completion(.success(username!))
                    }else{
                        completion(.failure(FirebaseError.wrongType))
                    }
                    return
                case .failure(let error):
                    print(error)
                    completion(.failure(error))
                }
            })
        }
        func retrieveXP(completion: @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            retrieveFromUsers(variableName: "xp", completion: completion)
        }
        
        func retrieveLevel(completion: @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            retrieveFromUsers(variableName: "level", completion: completion)
        }
        
        func retrieveName (completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveUserProperty(variableName: "username", completion: completion)
        }
        
        func retrieveBio (completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveUserProperty(variableName: "bio", completion: completion)
        }
        
        func retrieveInterest (completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveUserProperty(variableName: "interest", completion: completion)
        }
        
        //Database code to retrieve Image needs to be added
        
        func updateDB(collectionName: String, variableName: String, incrementBy: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            //sending user data to Firebase
            //        let uid = Auth.auth().currentUser!.uid
            //        let docRef = ref.collection(collectionName).document(uid)
            //        docRef.getDocument { (document, error) in
            //            if let document = document, document.exists {
            //                docRef.updateData([variableName: FieldValue.increment(incrementBy)])
            //let newValue = document.data()![variableName] as! Int
            //                completion(.success(newValue))
            //            } else {
            //                completion(.failure(FirebaseError.documentDoesntExist))
            //            }
            //        }
            //For sample purposes I will mimic response remove this in your actual code
            DispatchQueue.main.async {
                completion(.success(Int.random(in: 0...200) + incrementBy))
                
            }
        }
        
        func updateDB(collectionName: String, variableName: String, value: String, completion:  @escaping (Result<String, Error>) -> Void) {
            print(#function)
            //sending user data to Firebase
            //        let uid = Auth.auth().currentUser!.uid
            //        let docRef = ref.collection(collectionName).document(uid)
            //        docRef.getDocument { (document, error) in
            //            if let document = document, document.exists {
            //                docRef.updateData([variableName: value])
            //let newValue = document.data()![variableName] as! Int
            //                completion(.success(newValue))
            //            } else {
            //                completion(.failure(FirebaseError.documentDoesntExist))
            //            }
            //        }
            //For sample purposes I will mimic response remove this in your actual code
            DispatchQueue.main.async {
                
                let strings = ["apple", "orange", "banana", "kiwi", "startfruit"]
                completion(.success(strings.randomElement()!))
                
            }
        }
        func updateDB(collectionName: String, variableName: String, value: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            //sending user data to Firebase
            //        let uid = Auth.auth().currentUser!.uid
            //        let docRef = ref.collection(collectionName).document(uid)
            //        docRef.getDocument { (document, error) in
            //            if let document = document, document.exists {
            //                docRef.updateData([variableName: value])
            //let newValue = document.data()![variableName] as! Int
            //                completion(.success(newValue))
            //            } else {
            //                completion(.failure(FirebaseError.documentDoesntExist))
            //            }
            //        }
            //For sample purposes I will mimic response
            DispatchQueue.main.async {
                completion(.success(Int.random(in: 0...200)))
                
            }
        }
        func updateUsers(variableName: String, value: String, completion:  @escaping (Result<String, Error>) -> Void) {
            print(#function)
            updateDB(collectionName: "Users", variableName: variableName, value: value, completion: completion)
        }
        func updateUsers(variableName: String, value: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            updateDB(collectionName: "Users", variableName: variableName, value: value, completion: completion)
        }
        func updateUsers(variableName: String, incrementBy: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            updateDB(collectionName: "Users", variableName: variableName, incrementBy: incrementBy, completion: completion)
        }
        
        //Code to update Image will need to be added
    }
    
    ///将所有Firebase代码保留在此处
    类FirebaseManager{
    //private var ref=Firestore.Firestore()
    //private let store=Storage.Storage().reference()
    func retrieveFromDB(collectionName:String,variableName:String,completion:@escaping(Result)->Void){
    打印(#功能)
    //这是示例代码,可能有错误,因为我没有Firebase设置,但您可以查看逻辑,以便进行润色
    //guard let uid=Auth.Auth().currentUser?.uid else{
    //完成(.failure(firebasererror.notLoggedIn))
    //返回
    //        }
    //捕获当前用户的信息
    //设db=ref.collection(collectionName)
    //db.addSnapshotListener{[self](querySnapshot,错误)位于
    //
    //如果let error=error{
    //完成(.failure(error))
    //返回
    //            }
    //警卫(querySnapshot?.documents)!=无其他{
    //打印(“文档为空”)
    //完成(.failure(FirebaseError.emptyDocument))
    //返回
    //            }
    //让docRef=db。(文档(uid)
    //
    //docRef.getDocument{(快照,错误)位于
    //如果let error=error{
    //完成(.failure(error))
    //返回
    //                }
    //
    
    var body: some View {
        //All the code for the ForEach
    }
    
    ///Keep all the Firebase Code HERE
    class FirebaseManager{
        //private var ref = Firestore.firestore()
        //private let store = Storage.storage().reference()
        func retrieveFromDB(collectionName: String, variableName: String, completion:  @escaping (Result<Any, Error>) -> Void) {
            print(#function)
            //This is sample code, likely has errors because I dont have Firebase setup but you can see the logic so you can touch up
            
            //        guard let uid = Auth.auth().currentUser?.uid else {
            //            completion(.failure(FirebaseError.notLoggedIn))
            //            return
            //        }
            // catch the information of the current user
            //        let db = ref.collection(collectionName)
            //        db.addSnapshotListener { [self] (querySnapshot, error) in
            //
            //            if let error = error{
            //                completion(.failure(error))
            //                return
            //            }
            //            guard (querySnapshot?.documents) != nil else {
            //                print("Document is empty")
            //                completion(.failure(FirebaseError.emptyDocument))
            //                return
            //            }
            //            let docRef = db.(document(uid)
            //
            //            docRef.getDocument { (snapshot, error) in
            //                if let error = error{
            //                    completion(.failure(error))
            //                    return
            //                }
            //
            //            completion(.success(snapshot.get(variableName)))
            //            }
            //        }
            //For sample purposes I will mimic response remove this in your actual code
            DispatchQueue.main.async {
                if variableName == "xp" || variableName == "level"{
                    completion(.success(Int.random(in: 0...200)))
                }else{
                    let strings = ["apple", "orange", "banana", "kiwi", "startfruit"]
                    completion(.success(strings.randomElement()!))
                }
            }
        }
        ///For Int variables
        func retrieveFromUsers(variableName: String, completion: @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            retrieveFromDB(collectionName: "Users", variableName: variableName, completion: {result in
                switch result {
                case .success(let value):
                    let xp = value as? Int
                    if xp != nil{
                        completion(.success(xp!))
                    }else{
                        completion(.failure(FirebaseError.wrongType))
                    }
                    return
                case .failure(let error):
                    print(error)
                    completion(.failure(error))
                }
            })
        }
        ///For String variables
        func retrieveUserProperty(variableName: String, completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveFromDB(collectionName: "Users", variableName: variableName, completion: {result in
                switch result {
                case .success(let value):
                    let username = value as? String
                    if username != nil{
                        completion(.success(username!))
                    }else{
                        completion(.failure(FirebaseError.wrongType))
                    }
                    return
                case .failure(let error):
                    print(error)
                    completion(.failure(error))
                }
            })
        }
        func retrieveXP(completion: @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            retrieveFromUsers(variableName: "xp", completion: completion)
        }
        
        func retrieveLevel(completion: @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            retrieveFromUsers(variableName: "level", completion: completion)
        }
        
        func retrieveName (completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveUserProperty(variableName: "username", completion: completion)
        }
        
        func retrieveBio (completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveUserProperty(variableName: "bio", completion: completion)
        }
        
        func retrieveInterest (completion: @escaping (Result<String, Error>) -> Void) {
            print(#function)
            retrieveUserProperty(variableName: "interest", completion: completion)
        }
        
        //Database code to retrieve Image needs to be added
        
        func updateDB(collectionName: String, variableName: String, incrementBy: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            //sending user data to Firebase
            //        let uid = Auth.auth().currentUser!.uid
            //        let docRef = ref.collection(collectionName).document(uid)
            //        docRef.getDocument { (document, error) in
            //            if let document = document, document.exists {
            //                docRef.updateData([variableName: FieldValue.increment(incrementBy)])
            //let newValue = document.data()![variableName] as! Int
            //                completion(.success(newValue))
            //            } else {
            //                completion(.failure(FirebaseError.documentDoesntExist))
            //            }
            //        }
            //For sample purposes I will mimic response remove this in your actual code
            DispatchQueue.main.async {
                completion(.success(Int.random(in: 0...200) + incrementBy))
                
            }
        }
        
        func updateDB(collectionName: String, variableName: String, value: String, completion:  @escaping (Result<String, Error>) -> Void) {
            print(#function)
            //sending user data to Firebase
            //        let uid = Auth.auth().currentUser!.uid
            //        let docRef = ref.collection(collectionName).document(uid)
            //        docRef.getDocument { (document, error) in
            //            if let document = document, document.exists {
            //                docRef.updateData([variableName: value])
            //let newValue = document.data()![variableName] as! Int
            //                completion(.success(newValue))
            //            } else {
            //                completion(.failure(FirebaseError.documentDoesntExist))
            //            }
            //        }
            //For sample purposes I will mimic response remove this in your actual code
            DispatchQueue.main.async {
                
                let strings = ["apple", "orange", "banana", "kiwi", "startfruit"]
                completion(.success(strings.randomElement()!))
                
            }
        }
        func updateDB(collectionName: String, variableName: String, value: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            //sending user data to Firebase
            //        let uid = Auth.auth().currentUser!.uid
            //        let docRef = ref.collection(collectionName).document(uid)
            //        docRef.getDocument { (document, error) in
            //            if let document = document, document.exists {
            //                docRef.updateData([variableName: value])
            //let newValue = document.data()![variableName] as! Int
            //                completion(.success(newValue))
            //            } else {
            //                completion(.failure(FirebaseError.documentDoesntExist))
            //            }
            //        }
            //For sample purposes I will mimic response
            DispatchQueue.main.async {
                completion(.success(Int.random(in: 0...200)))
                
            }
        }
        func updateUsers(variableName: String, value: String, completion:  @escaping (Result<String, Error>) -> Void) {
            print(#function)
            updateDB(collectionName: "Users", variableName: variableName, value: value, completion: completion)
        }
        func updateUsers(variableName: String, value: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            updateDB(collectionName: "Users", variableName: variableName, value: value, completion: completion)
        }
        func updateUsers(variableName: String, incrementBy: Int, completion:  @escaping (Result<Int, Error>) -> Void) {
            print(#function)
            updateDB(collectionName: "Users", variableName: variableName, incrementBy: incrementBy, completion: completion)
        }
        
        //Code to update Image will need to be added
    }
    
    import SwiftUI
    import CoreData
    //Capitalized no other changes here
    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() {
            print(#function)
        }
        
        init(_ name:String, _ xp: Int) {
            print(#function)
            self.name = name
            self.xp = xp
            self.level = self.xp2Level(xp: xp)
        }
        
        func xp2Level(xp:Int) -> Int {
            print(#function)
            if xp < 9500 {
                return xp / 500 + 1
            }
            else if xp < 29500 {
                return (xp - 9500) / 1000 + 1
            }
            else {
                return (xp - 29500) / 2000 + 1
            }
        }
    }
    //This is to standardize what comes from your Firebase Code. Try to condense code that is duplicated
    enum FirebaseError: Error {
        case notLoggedIn
        case emptyDocument
        case wrongType
        case documentDoesntExist
    }
    
    Capitalize
    class UserViewModel: ObservableObject {
        let alertVM = AlertViewModel.shared
        @Published var user: UserModel = UserModel()
        @Published var isLoading = false
        //AppStorage wont work here
        var status: Bool{
            get{
                UserDefaults.standard.bool(forKey: "status")
            }
            set{
                UserDefaults.standard.set(newValue, forKey: "status")
            }
            
        }
        //Separate all Firebase Code
        let firebaseManager = FirebaseManager()
        
        init() {
            populateAllVariables()
        }
        
        func increaseXPnLV() {
            print(#function)
            //sending xp to Firebase
            firebaseManager.updateUsers(variableName: "xp", incrementBy: 50, completion: {result in
                switch result {
                case .success(let newXp):
                    self.user.xp = newXp
                    //sending level to Firebase
                    self.firebaseManager.updateUsers(variableName: "level", value: self.user.xp2Level(xp: newXp), completion: {result in
                        switch result {
                        case .success(let newLevel):
                            print("newLevel = \(newLevel)")
                            self.user.level = newLevel
                            self.alertVM.scheduleAlert(title: "Congratulations!", message: "You completed a goal today, XP+50!")
                            return
                        case .failure(let error as NSError):
                            //Show alert here
                            self.alertVM.scheduleAlert(error: error)
                            print(error)
                        }
                    })
                    return
                case .failure(let error):
                    //Show alert here
                    self.alertVM.scheduleAlert(error: error)
                    print(error)
                    
                }
            })
        }
        func populateAllVariables() {
            print(#function)
            getXP()
            getLevel()
            getName()
            getBio()
            getInterest()
        }
        public func getXP() {
            print(#function)
            firebaseManager.retrieveXP(completion: {result in
                switch result {
                case .success(let xp):
                    self.user.xp = xp
                case .failure(let error):
                    //Show alert here
                    self.alertVM.scheduleAlert(error: error)
                    print(error)
                }
            })
        }
        
        public func getLevel() {
            print(#function)
            firebaseManager.retrieveLevel(completion: {result in
                switch result {
                case .success(let level):
                    self.user.level = level
                case .failure(let error):
                    //Show alert here
                    self.alertVM.scheduleAlert(error: error)
                    print(error)
                }
            })
        }
        
        public func getName() {
            print(#function)
            firebaseManager.retrieveName(completion: {result in
                switch result {
                case .success(let name):
                    self.user.name = name
                case .failure(let error):
                    //Show alert here
                    self.alertVM.scheduleAlert(error: error)
                    print(error)
                }
            })
        }
        
        public func getBio() {
            print(#function)
            firebaseManager.retrieveBio(completion: {result in
                switch result {
                case .success(let bio):
                    self.user.bio = bio
                case .failure(let error):
                    //Show alert here
                    self.alertVM.scheduleAlert(error: error)
                    print(error)
                }
            })
        }
        
        public func getInterest() {
            print(#function)
            firebaseManager.retrieveInterest(completion: {result in
                switch result {
                case .success(let interest):
                    self.user.interest = interest
                case .failure(let error):
                    //Show alert here
                    self.alertVM.scheduleAlert(error: error)
                    print(error)
                }
            })
        }
        ///This will need work
        //    public func getPhoto() -> Data {
        //        updatePhoto(completion: {
        //            return (self.user.image) as Data
        //        })
        //    }
        //It is best to separate work from the View
        func deleteGoal(moc: NSManagedObjectContext, goal: Goal) -> Bool{
            print(#function)
            var result = false
            moc.performAndWait  {
                moc.delete(goal)
                do{
                    try moc.save()
                    result = true
                }catch{
                    self.alertVM.scheduleAlert(error: error)
                    result = false
                }
            }
            return result
        }
    }
    //This is to centralize alerts. When you are using the web there will be errors and therefore alerts that the user should be aware of 
    struct CustomAlert: Identifiable {
        let id: UUID = UUID()
        let title: String
        let message: String
        let dismissButtonTitle: String
    }
    //Again to centralize the alerts. I like putting this on the uppermost View so you can send alerts from anywhere
    class AlertViewModel: ObservableObject {
        //Singleton keeps everything connected
        static let shared: AlertViewModel = AlertViewModel()
        @Published var currentAlert: CustomAlert?
        private init() {
            //Required because you need to share the instance
        }
        //Use this for a custom message
        func scheduleAlert(title: String = "ERROR", message: String, dismissButtonTitle: String = "OK") {
            currentAlert = CustomAlert(title: title, message: message, dismissButtonTitle: dismissButtonTitle)
        }
        //Use this if you have a fully formed Error
        func scheduleAlert(error: Error) {
            let error = error as NSError
            currentAlert = CustomAlert(title: "ERROR", message:  (error.localizedFailureReason ?? "") + error.localizedDescription + (error.localizedRecoverySuggestion ?? ""), dismissButtonTitle: "OK")
        }
        
    }
    struct Goals: View {
        //The View should never be aware of where your data is stored. all Firebase code should be removed
        @StateObject var currentUser: UserViewModel = UserViewModel()
        //This observes the alerts that are sent from anywhere
        @StateObject var alertVM: AlertViewModel = AlertViewModel.shared
        //No code provided
        //@StateObject var homeData = HomeViewModel()
        @FetchRequest(entity: Goal.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Goal.date, ascending: true)], animation: .spring()) var results : FetchedResults<Goal>
        
        @Environment(\.managedObjectContext) var context
        var body: some View {
            VStack{
                Text("Name = " + currentUser.user.name.description)
                Text("Level = " + currentUser.user.level.description)
                Text("XP = " + currentUser.user.xp.description)
                ForEach(results){goal in
                    Button(action: {
                        //There should be some kind of check here to make sure the goal got deleted
                        if currentUser.deleteGoal(moc: context, goal: goal){
                            //No code provided
                            //if current_user_id != nil {
                            currentUser.increaseXPnLV()
                        }
                        //}
                    }, label: {
                        //Missing Brackets
                        Text("Goal \(goal.name?.description ?? "") Completed")
                        
                    })
                    //This gets presented from everywhere
                    .alert(item: $alertVM.currentAlert, content: {current in
                        Alert(title: Text(current.title), message: Text(current.message), dismissButton: .cancel(Text(current.dismissButtonTitle)))
                    })
                    
                }
            }
        }
    }