How can I use @FetchRequest
in SwiftUI with a fetch request based on a variable being passed in from a parent view, while also ensuring that the view updates based on Core Data changes?
I have this issue where using @FetchRequest
in SwiftUI while passing in a variable to the fetch request doesn't work. It results in the following error:
Cannot use instance member 'name' within property initializer; property initializers run before 'self' is available
struct DetailView: View {
@FetchRequest(fetchRequest: Report.fetchRequest(name: name), animation: .default)
private var data: FetchedResults<Report>
let name: String
var body: some View {
Text("\(data.first?.summary.text ?? "")")
.navigationTitle(name)
.onAppear {
ReportAPI.shared.fetch(for: name) // Make network request to get Report data then save to Core Data
}
}
}
extension Report {
@nonobjc public class func fetchRequest(name: String) -> NSFetchRequest<Report> {
let fetchRequest = NSFetchRequest<Report>(entityName: "Report")
fetchRequest.fetchLimit = 1
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Report.createdAt, ascending: true)]
fetchRequest.predicate = NSPredicate(format: "details.name == %@", name)
return fetchRequest
}
}
This view is pushed using a NavigationLink
from a previous view. Like: NavigationLink(destination: DetailView(name: item.name))
.
I've looked at this answer and I don't think that it will work for my use case since normally the @FetchRequest
property wrapper automatically listens for data changes and updates automatically. Since I'm doing an async call to make a network request and update Core Data, I need the data
variable to update dynamically once that is complete.
I've also looked at this answer but I think it has some of the same problems as mentioned above (although I'm not sure about this). I'm also getting an error using that code on the self.data = FetchRequest(fetchRequest: Report.fetchRequest(name: name), animation: .default)
line. So I'm not sure how to test my theory here.
Cannot assign to property: 'data' is a get-only property
struct DetailView: View {
@FetchRequest
private var data: FetchedResults<Report>
let name: String
var body: some View {
Text("\(data.first?.summary.text ?? "")")
.navigationTitle(name)
.onAppear {
ReportAPI.shared.fetch(for: name) // Make network request to get Report data then save to Core Data
}
}
init(name: String) {
self.name = name
self.data = FetchRequest(fetchRequest: Report.fetchRequest(name: name), animation: .default)
}
}
Therefore, I don't think that question is the same as mine, since I need to be sure that the view updates dynamically based on Core Data changes (ie. when the fetch
method saves the new data to Core Data.