As Natascha notes in her helpful article
https://tanaschita.com/20230807-migrating-to-observation/
pre-iOS17 was like this,
Stateview Subview
-----------------------------------------
Value Type @State @Binding
Ref Type @StateObject @ObservedObject
With iOS 17, it's like this:
Stateview Subview
-----------------------------------------
Value Type @State @Binding
Ref Type @State @Bindable
I like how they simplified @State and @StateObject into just @State for both cases. I'm curious, though, why didn't they simplify @Binding and @ObservedObject into just @Binding? Why did they need to maintain the separate property wrapper @Bindable? I'm sure there's a good reason, just wondering if anybody knew why.
Interestingly, you can use both @Binding and @Bindable, and they both seem to work. I know that you're supposed to use @Bindable here, but curious why @Binding works also.
import SwiftUI
@Observable
class TestClass {
var myNum: Int = 0
}
struct ContentView: View {
@State var testClass1 = TestClass()
@State var testClass2 = TestClass()
var body: some View {
VStack {
Text("testClass1: \(testClass1.myNum)")
Text("testClass2: \(testClass2.myNum)")
// Note the passing of testClass2 without $. Xcode complains otherwise.
ButtonView(testClass1: $testClass1, testClass2: testClass2)
}
.padding()
}
}
struct ButtonView: View {
@Binding var testClass1:TestClass
@Bindable var testClass2:TestClass
var body: some View {
Button(action: {
testClass1.myNum += 1
testClass2.myNum += 2
} , label: {
Text("Increment me")
})
}
}
Ok. This explanation helps more with where your thinking's at.
First of all, after doing some testing, you are correct in saying @State and @Binding now work with reference types. This seems a little strange to me as in the earlier betas I tried this and views weren't being updated (what I thought should happen). So maybe something has changed since then, I'm not sure. It does however make @Bindable sort of in a strange place as bindings can just be extracted from State or Binding.
Hopefully, the documentation can be updated to show what property wrapper needs to be used for what, because at the moment it seems like they all do similar things now.
Secondly:
and just changed the name of @ObservedObject into @Bindable
This isn't technically true. @ObservedObject was needed regardless in order for SwiftUI to watch the model object's properties for changes. Now SwiftUI can watch for changes without a property wrapper, and more efficiently too: only when properties that are accessed change will the view be reloaded.
@Bindable is more of an attachment to the model allowing binding creation. I don't think it does anything regarding observation itself.