Hmmm. I guess it is not the property wrapper that accesses the environment of its enclosing object. Instead, SwiftUI injects the environment in the wrapper. But how?
FetchRequest only declares conformance to DynamicProperty, a protocol that still doesn't solve this mystery.
This is exact, @malhal! It takes time to understand how DynamicProperty can be used. Take a look at GRDBQuery one day: it brings @FetchRequest powers to raw SQLite :-)
GRDBQuery is an interesting demo of DynamicProperty however I don't agree with the same application that made a change to the database hitting the database again just to find out what changes it made! (It can't detect-cross process changes) You'd be better off with a model layer.
Sure, and GRDB won't prevent you from building your proper model layer: the library is architecture-agnostic. This does not mean it doesn't care about architecture: on the contrary, it cares a lot that developer teams feel at ease, and can build their layers in their preferred way. I hope you'd feel at home there.
On top of that, built-in database observation is useful, because it is very robust. GRDB can even detect changes performed by raw SQL queries, as well as indirect changes triggered by foreign keys actions or SQL triggers: basically it does not miss anything that happens in a given process. Relying on built-in observation means that you don't have to write code, forget things, think about concurrency, make mistakes, and ship bugs.
struct FetchRequest2<ResultType>: DynamicProperty {
@Environment(\.managedObjectContext) private var context
@StateObject private var controller = FetchController<ResultType>()
init(params...) {
self.params = params
}
public var wrappedValue: Result<[ResultType], Error> {
return controller.result(for: viewContext, other params...)
}
}
Whenever the environment var changes, body will be called in the View that installs this DynamicProperty which should lead to wrappedValue being called again and the environment var will be the latest value.