I'm experimenting with SwiftUI and Combine, and wanted to be able to receive notification whenever an array of struct items changes (either changes within items, or changes to the array, i.e. append, remove).
I tried the following code, but all I get, given an input array of three elements, is a receiveValue for each of those three initials, and nothing else even when changes are made to the array through the UI (which correctly reflects the changes). It's as if its a fire once publisher.
struct Item: Identifiable {
var id = UUID()
var title: String
}
class ItemStore: ObservableObject {
@Published var items: [Item]
private var cancellables = Set<AnyCancellable>()
init(items: [Item] = []) {
self.items = items
self.items.publisher
.sink(receiveValue: {
print("save=\($0)")
})
.store(in: &cancellables)
}
}
After some playing around, I tried the following, which then receives a receiveValue containing the entire array, and does so for each futher update. This would actually suffice for my current experiment, but doesn't seem like how it should be done, poking into the internals of the @Published array.
struct Item: Identifiable {
var id = UUID()
var title: String
}
class ItemStore: ObservableObject {
@Published var items: [Item]
private var cancellables = Set<AnyCancellable>()
init(items: [Item] = []) {
self.items = items
self._items.projectedValue
.sink(receiveValue: {
print("save=\($0)")
})
.store(in: &cancellables)
}
}
I guess the crux of the question is, what is the right way to receive notifications over the lifecycle of the app for:
- An array
- The elements of an array
NB: I'm aware that I can suppress the initial assignment using the .dropFirst method (optionally specifying the number of elements to skip).
The ItemStore instance is passed in using environmentObject and accessed using @EnvironmentObject.
I'm aware there might be much better ways to respond to changes for persisting state, but this still seems valid for a trivial app.