TabView中的EnvironmentObject-SwiftUI

时间:2020-11-08 05:17:36

标签: swift swiftui

在我的应用中,我有一份支出清单。我正在尝试让我的UserSettings对象在TabView中链接的所有视图之间共享。

基本上,当PayScheduleForm中的userSettings.date更改时,我希望ExpenseList谓词中的userSettings.date的值更改。

我相信做到这一点的方法是使用EnvironmentObject。启动我的应用程序时,出现以下错误。我已经看到一些与此错误相关的链接,但似乎没有一个可以解决我的问题。

Thread 1: Fatal error: No ObservableObject of type UserSettings found. A View.environmentObject(_:) for UserSettings may be missing as an ancestor of this view.

这是我当前的代码:

SceneDelegate.swift

    var window: UIWindow?
    var settings = UserSettings()
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = MainView().environment(\.managedObjectContext, coreDataStack.viewContext).environmentObject(settings)

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

MainView.swift


import SwiftUI
import CoreData



@available(iOS 14.0, *)
struct MainView: View {
    @EnvironmentObject var userSettings: UserSettings
    
    @Environment(\.managedObjectContext)
    var context: NSManagedObjectContext
    
    var nextPaydate: Date{
        return Calendar.current.date(byAdding: .day, value: 14, to: userSettings.date ) ?? Date()
    }
    
    var body: some View {
        TabView {
            
            DashboardView()
                .tabItem {
                    VStack {
                        Text("Dashboard")
                        Image(systemName: "chart.pie")
                    }
            }
            .tag(0)
            
            ExpenseList(predicate: NSPredicate(format: "expenseDate >= %@ AND expenseDate < %@", userSettings.date as NSDate, nextPaydate as NSDate), sortDescriptor: NSSortDescriptor(key: "expenseDate", ascending: true))
                .tabItem {
                    VStack {
                        Text("Expense List")
                        Image(systemName: "list.dash")
                    }
            }
            .tag(1)

            SettingsView()
                .tabItem {
                    VStack {
                        Text("Settings")
                        Image(systemName: "gearshape")
                    }
            }
            .tag(2)
            NewDashboard()
                .tabItem {
                    VStack {
                        Text("TEST")
                        Image(systemName: "exclamationmark.square")
                    }
            }
            .tag(3)
        }
        .environmentObject(userSettings)
        .onAppear(perform: changePayPeriod)
    }
    @available(iOS 14.0, *)
    func changePayPeriod(){
        let currentDate = Date()
        if currentDate > PayScheduleForm().nextPaydate{
            self.userSettings.date = PayScheduleForm().nextPaydate
        }

    }
}



@available(iOS 14.0, *)
struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}

SettingsView.swift


import SwiftUI
import CoreData



struct SettingsView: View {
    @State var accounts: String = ""
    @Environment(\.managedObjectContext)
    
    var context: NSManagedObjectContext
    
    @EnvironmentObject var userSettings: UserSettings
    var logToEdit: Accounts?
    var body: some View {
        NavigationView{
            if #available(iOS 14.0, *) {
                List{
                    NavigationLink(destination: AccountsList()) {
                        Text("Accounts")
                    }
                    NavigationLink(destination: CategoriesList()) {
                        Text("Categories")
                    }
                    NavigationLink(destination: PayScheduleForm()) {
                        Text("Pay Schedule")
                    }
                }.navigationTitle("Settings")
            } else {
                // Fallback on earlier versions
            }
            
        }
        .environmentObject(userSettings)
        .onAppear(perform: {
            getUserDefaults()
        })
    }
    
    func getPayDate() -> Date{
        var date = Date()
        if UserDefaults.standard.object(forKey: "payDate") != nil {
            date = UserDefaults.standard.object(forKey: "payDate") as! Date
        }
        let df = DateFormatter()
        df.dateFormat = "MM/dd/yyyy"
        print(df.string(from: date))
        
        return date
    }
    
    func getUserDefaults(){
        var date = Date()
        if UserDefaults.standard.object(forKey: "payDate") != nil {
            date = UserDefaults.standard.object(forKey: "payDate") as! Date
        }
        let df = DateFormatter()
        df.dateFormat = "MM/dd/yyyy"
        print(df.string(from: date))

    }

}

struct SettingsView_Previews: PreviewProvider {
    static var previews: some View {
        SettingsView()
    }
}


PayScheduleForm.swift



import SwiftUI
import CoreData


@available(iOS 14.0, *)
struct PayScheduleForm: View {
    var frequencies = ["Bi-Weekly"]
    
    @Environment(\.managedObjectContext) var context
    
    @EnvironmentObject var userSettings : UserSettings
    
    var currentPayDate: Date {
        let calendar = NSCalendar.current
        return calendar.startOfDay(for: userSettings.date) << Error shown here
    }
    
    var nextPaydate: Date{
        return Calendar.current.date(byAdding: .day, value: 14, to: currentPayDate ) ?? Date()
    }

    
    var nextPaydateText: String{
        return Utils.dateFormatterMed.string(from: nextPaydate)
    }
    
    var prevMonthPayStart: Date{
        return Calendar.current.date(byAdding: .month, value: -1, to: currentPayDate ) ?? Date()
    }
    
    var prevMonthPayEnd: Date{
        return Calendar.current.date(byAdding: .month, value: -1, to: nextPaydate ) ?? Date()
        
    }
    
    var prevMonthPayNextCheck: Date{
        return Calendar.current.date(byAdding: .day, value: 14, to: prevMonthPayEnd ) ?? Date()
        
    }
    
    var prevWkPayStart: Date{
        return Calendar.current.date(byAdding: .day, value: -7, to: currentPayDate ) ?? Date()
    }
    
    var body: some View {
        Form{
            TextField("Paycheck Amount", text: $userSettings.payAmount)
            Picker(selection: $userSettings.frequency, label: Text("Pay Frequency")) {
                    ForEach(0 ..< frequencies.count) {
                        Text(self.frequencies[$0]).tag(userSettings.frequency)
                    }

                }

            DatePicker(selection: $userSettings.date, displayedComponents: .date) {
                    Text("Last Payday")
                }

            
            
            
        }.navigationTitle("Pay Settings")
        
        Text("Next Payday: \(nextPaydateText)")
        }

    
}

//struct PayScheduleForm_Previews: PreviewProvider {
//    static var previews: some View {
//        PayScheduleForm()
//    }
//}

1 个答案:

答案 0 :(得分:0)

您的MainView本地属性会隐藏环境对象,因此只需将其删除,userSettings将作为注入的EnvironmentObject可用

@available(iOS 14.0, *)
struct MainView: View {
//    var userSettings = UserSettings()  // << remove !!
  @EnvironmentObject var userSettings: UserSettings    // << add !!