I have an @Published field that dictates whether the user is currently in offline mode.
class RequestStatus: ObservableObject {
static var shared = RequestStatus()
@Published var offlineModeActive: Bool = false
private init() {}
}
Throughout my app, I use the Combine framework to subscribe to changes in this field and perform some work.
import Combine
class ExampleClass {
var offlineModeCancellable: AnyCancellable
init() {
self.offlineModeCancellable = RequestStatus.shared.$offlineModeActive.sink(receiveValue: { offlineModeActive in
// Perform work
})
}
}
This works fine, however, when I run unit tests I do not want changes on this field to be published because I want to set up the environment of the test manually.
Therefore, I added in a field called shouldPublishChanges
that defines whether changes should be published. If this is set to true, only then will I manually call the objectWillChange.send()
method.
class RequestStatus: ObservableObject {
static var shared = RequestStatus()
var shouldPublishChanges: Bool = false
var offlineModeActive: Bool = false {
willSet {
if shouldPublishChanges {
objectWillChange.send()
}
}
}
private init() {}
}
I then updated my Combine subscriber to subscribe to changes on the RequestStatus.shared.objectwillChange
value meaning it should only receive a value when shouldPublishChanges is set to true (or so I thought).
import Combine
class ExampleClass {
var offlineModeCancellable: AnyCancellable
init() {
self.offlineModeCancellable = RequestStatus.shared.objectWillChange.sink(receiveValue: {
// Perform work
})
}
}
However, even though shouldPublishChanges
is set to shouldPublishChanges
, if I change the offlineModeActive
value, the value is published and the subscriber still receives the update and performs the work.
So, how do I conditionally publish changes to a Combine subscriber?
The only other idea I have is to have one field that stores the value and another field for the publisher. Then, only when I want to publish changes to this field will I update the published value.
import Combine
class RequestStatus: ObservableObject {
private init() {}
static var shared = RequestStatus()
var shouldPublishChanges: Bool = false
private(set) var offlineModeActivePublisher = CurrentValueSubject<Bool, Never>(false)
private(set) var offlineModeActive: Bool = false
func updateOfflineModeActive(offlineModeActive: Bool) {
self.offlineModeActive = offlineModeActive
if shouldPublishChanges {
offlineModeActivePublisher.value = offlineModeActive
}
}
}
However:
Requires a lot of boiler-plate code for each field I want to do this for
I have two values that can be out of sync (this is less of a concern as
shouldPublishChanges
is set once and never changed)I feel like there is a better way of achieving the same thing.
Any ideas?