swiftcore-dataswiftuiobservableobjectfetchrequest

SwiftUI: ObservableObject doesn't work with fetchRequest init


I have an ObservableObject declared like this in my DateView:

import SwiftUI

    class SelectedDate: ObservableObject {
        @Published var selectedMonth: Date = Date()
        
        var startDateOfMonth: Date {
            let components = Calendar.current.dateComponents([.year, .month], from: self.selectedMonth)
            let startOfMonth = Calendar.current.date(from: components)!
            return startOfMonth
        }
    
        var endDateOfMonth: Date {
            var components = Calendar.current.dateComponents([.year, .month], from: self.selectedMonth)
            components.month = (components.month ?? 0) + 1
            let endOfMonth = Calendar.current.date(from: components)!
            return endOfMonth
        }
    }

struct DateView: View {
// other code
}

I can access startDateOfMonth and endDateOfMonth in other views like this:

Text("\(self.selectedDate.startDateOfMonth)")

But I have a problem when I try to use those variables from ObservableObject inside a fetchRequest initializer in my TransactionsListView:

    import SwiftUI
    
    struct TransactionsListView: View {
    
    @Environment(\.managedObjectContext) var managedObjectContext
        var fetchRequest: FetchRequest<NPTransaction>
        var transactions: FetchedResults<NPTransaction> { fetchRequest.wrappedValue }
    @EnvironmentObject var selectedDate: SelectedDate

    // other code
            init() {
                    fetchRequest = FetchRequest<NPTransaction>(entity: NPTransaction.entity(), sortDescriptors: [
                        NSSortDescriptor(keyPath: \NPTransaction.date, ascending: false)
                    ], predicate: NSPredicate(format: "date >= %@ AND date < %@", self.selectedDate.startDateOfMonth as NSDate, self.selectedDate.endDateOfMonth as NSDate))
            }
    
    var body: some View {
    // other code
    }
    }

I am getting an error:

Variable 'self.fetchRequest' used before being initialized

What ma I doing wrong? I have tried to use those variables inside init without self. Same error. The only way it worked was if those startDateOfMonth and endDateOfMonth were not in ObservableObject, but as a vars in ancestor view which I was passing as parameters to my view with fetchRequest init. But I have few views like this and wanted to use ObservableObject, not to pass the same parameters to subviews all the time.


Solution

  • The problem is that you can not use @EnvironmentObject in the init(). The possible option here is to pass the EnvironmentObject as parameter to the View. Then use that parameter inside the init. Here is the constructor for the view, then you can access start and endTime with local variable selectedDate.

    init(selectedDate : SelectedDate) 
    {
       //now you can access selectedDate here and use it in FetchRequest
       fetchRequest = FetchRequest<NPTransaction>(entity: NPTransaction.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \NPTransaction.date, ascending: false)], predicate: NSPredicate(format: "date >= %@ AND date < %@", selectedDate.startDateOfMonth as NSDate, selectedDate.endDateOfMonth as NSDate))
    }
    

    Where you call that view, pass the EnvironmentObject as parameter.

                                        //Declared as Environment Object
    TransactionsListView(selectedDate : self.selectedDate)