Skip to content

Instantly share code, notes, and snippets.

@albertbori
Last active February 23, 2023 18:54
Show Gist options
  • Save albertbori/b7998b5d625fc2c93cfe31ccda3f49bf to your computer and use it in GitHub Desktop.
Save albertbori/b7998b5d625fc2c93cfe31ccda3f49bf to your computer and use it in GitHub Desktop.
SwiftUI willSet vs didSet onReceive
// Credit: Michael LaRandeau (@mlarandeau)
import SwiftUI
import Combine
import PlaygroundSupport
class ValueProvider: ObservableObject {
private let didSetSubject = CurrentValueSubject<Int, Never>(0)
@Published var value: Int = 0 {
didSet {
didSetSubject.send(value)
}
}
var didSetPublisher: AnyPublisher<Int, Never> {
didSetSubject.eraseToAnyPublisher()
}
func randomize() {
value = Int.random(in: 0..<1000)
}
}
struct TestView: View {
@StateObject var valueProvider = ValueProvider()
@State var incrementor: Int = 0
var body: some View {
print("## Body")
return VStack(spacing: 20) {
Text("\(valueProvider.value)")
// If you use valueProvider.didSetPublisher here instead of $value, the onReceive closure gets called multiple times.
.onReceive(valueProvider.$value) {
print("## Update Value: \($0)")
// If you use the `didSetPublisher` above in onReceive and uncomment the line below, you will trigger an infinite loop
// incrementor += 1
}
Text("\(incrementor)")
Button("Change Number") {
valueProvider.randomize()
}
}
}
}
PlaygroundPage.current.setLiveView(TestView())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment