SwiftUI - is it possible to get didSet to fire when changing a @Published struct?
You can subscribe to the @Published
value stream in the class itself.
final class SomeStore: ObservableObject {
@Published var someOtherValue: String = "Waiting for didSet"
@Published var paddingRect: PaddingRect = PaddingRect()
private var subscribers: Set<AnyCancellable> = []
init() {
$paddingRect.sink { paddingRect in
print(paddingRect) // ð
}.store(in: &subscribers)
}
}
Note that the
sink
closure will be called onwillSet
, though.
The property observer observes the property. The trouble goes from new Swift syntax related to property wrappers. In your case you try to observe if value of Published (which is a struct defining the specialized property wrapper) did change, not the value of the wrapped property.
If you need to monitor left or right values in PaddingRect, simply observe this values directly.
import SwiftUI
struct PaddingRect {
var left: CGFloat = 20 {
didSet {
print("left padding change from:", oldValue, "to:", left)
}
}
var right: CGFloat = 20 {
didSet {
print("right padding change from:", oldValue, "to:", right)
}
}
}
final class SomeStore : ObservableObject {
@Published var someOtherValue: String = "Waiting for didSet"
@Published var paddingRect:PaddingRect = PaddingRect()
}
struct ContentView: View {
@ObservedObject var store = SomeStore()
var body: some View {
VStack {
Spacer()
Rectangle()
.fill(Color.yellow)
.padding(.leading, store.paddingRect.left)
.padding(.trailing, store.paddingRect.right)
.frame(height: 100)
Text(store.someOtherValue)
HStack {
Button(action: {
// This doesn't call didSet
self.store.paddingRect.left += 20
// This does call didSet, ie. setting the whole thing
self.store.paddingRect = PaddingRect(
left: self.store.paddingRect.left + 20,
right: self.store.paddingRect.right
)
}) {
Text("Padding left +20")
}
Button(action: {
self.store.paddingRect.right += 20
}) {
Text("Padding right +20")
}
}
Spacer()
}
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Or take the advantage that Published projected value is Publisher and aply next modifier to any View
.onReceive(store.$paddingRect) { (p) in
print(p)
}