Hi!
While the @Obsevable macro seems to make things easier at first glance, I am struggling to understand how to implement some scenarious using the new observability model - most importantly, how to observe properties within the same model class.
For example, consider the following model:
class MyModel: ObservableObject {
@Published var items = ["one", "two", "three"]
@Published var filter: String? = nil
@Published var filteredItems: [String] = []
init() {
$filter
.combineLatest($items)
.map { filter, items in
items.filter { filter == nil || $0.contains(filter!) }
}
.assign(to: &$filteredItems)
}
}
All @Published properties are easily accessible by the view, but I can also combine them inside the init method to compute filtered items whenever any of these values change. I don't seem to find a soluton for this using @Observable.
I tried using withObservationTracking, but this ends up with the view being continously redrawn. I tried to use this gist with the same effect: https://gist.github.com/SmartJSONEditor/33d796e81554205fd491b6449376c426.
@Observable class MyModel1 {
var items = ["one", "two", "three"]
var filter: String? = nil
var filteredItems: [String] = []
init() {
let filter = publisher(keyPath: \MyModel1.filter)
let items = publisher(keyPath: \MyModel1.items)
filter
.combineLatest(items)
.map { filter, items in
items.filter { filter == nil || $0.contains(filter!) }
}
.sink { filteredItems in
self.filteredItems = filteredItems
}
}
}
In the official observability proposal from Swift there is an example from the Fruta app, but this example uses a computed property. It does work in some cases, but it requires an observer and if there are more than one, the whole conputation is executed multiple times.
@Observable class MyModel2 {
var items = ["one", "two", "three"]
var filter: String? = nil
var filteredItems: [String] {
items.filter { filter == nil || $0.contains(filter!) }
}
}