hi david,
would it be enough for you to know if any @Published
property of an ObservableObject has changed (without having to watch each one individually)?
if so, consider having the object subscribe to its own objectWillChange
publisher. this seems to work:
import Combine
class SelfListener: ObservableObject {
@Published var property1: Int = 0
@Published var property2: Int = 0
var hasChanged: Bool = false
var cancellables = Set<AnyCancellable>()
init() {
objectWillChange.sink { _ in
self.hasChanged = true
print("received objectWillChange")
}
.store(in: &cancellables)
}
}
you could test it this way (i do this in a basic command-line MacOS; i did not test in a Playground).
let selfListener = SelfListener()
print(selfListener.hasChanged) // prints false
selfListener.property1 = 3 // prints received objectWillChange
print(selfListener.hasChanged) // prints true
selfListener.property2 = 8 // prints received objectWillChange
print(selfListener.hasChanged) // prints true
as to my phrase this seems to work above, it could be a little concerning that my selfListener
object has a publisher to which the selfListener
object itself is subscribed. this could bring on nightmares of possible memory cycles; and if so, a deinit
method on the object might address the problem:
deinit {
cancellables.forEach({ $0.cancel() })
}
finally, if you have a main-level object with properties that are themselves classes that conform to ObservableObject
and you want to know whether they have been edited, then i suppose you could subscribe at the main level to each of their objectWillChange publishers as well. i did not test this
this was sort of fun to experiment with (if it even makes sense to do it). but in fact, it might just be enough to write your own property wrapper for use with properties you want to watch (in place of using @Published) that handles any set
of the property by setting a named boolean such as hasChanged
to true (and, if necessary, executing objectWillChange.send()).
hope that helps,
DMG