@Bindingと@Bindableって何が違うの?
動きの違い
class/@Binding
class Book: Identifiable {
var id = UUID()
var title: String = ""
var Read: Bool = false
}
import SwiftUI
struct ContentView: View {
@State var book = Book()
var body: some View {
VStack {
TextView(book: $book)
Toggle(isOn: $book.Read, label: {
Text("Read")
})
}
.padding()
}
}
struct TextView: View {
@Binding var book: Book
var body: some View {
Text(String(book.Read))
}
}
これだとtoggleをonoffしてもTextは変わらなかった!
class+ @Observable/@Binding
@Observable
class Book: Identifiable {
var id = UUID()
var title: String = ""
var Read: Bool = false
}
struct ContentView: View {
@State var book = Book()
var body: some View {
VStack {
TextView(book: $book)
Toggle(isOn: $book.Read, label: {
Text("Read")
})
}
.padding()
}
}
struct TextView: View {
@Binding var book: Book
var body: some View {
Text(String(book.Read))
}
}
これだとtoggleをonoffしたらTextは変わった!
class+ @Observable/@Bindable
@Observable
class Book: Identifiable {
var id = UUID()
var title: String = ""
var Read: Bool = false
}
struct ContentView: View {
@State var book = Book()
var body: some View {
VStack {
TextView(book: book)
Toggle(isOn: $book.Read, label: {
Text("Read")
})
}
.padding()
}
}
struct TextView: View {
@Bindable var book: Book
var body: some View {
Text(String(book.Read))
}
}
これだとtoggleをonoffしたらTextは変わった!
struct/@Binding
struct Book: Identifiable {
var id = UUID()
var title: String = ""
var Read: Bool = false
}
struct ContentView: View {
@State var book = Book()
var body: some View {
VStack {
TextView(book: $book)
Toggle(isOn: $book.Read, label: {
Text("Read")
})
}
.padding()
}
}
struct TextView: View {
@Binding var book: Book
var body: some View {
Text(String(book.Read))
}
}
これだとtoggleをonoffしたらTextは変わった!
@Bindable private var profile = Profile(name: "John Doe")
@Bindable var profile: Profile
両方使えるらしい
@StateObject→@Stateに
@ObservedObject→@Bindableに
@EnvironmentObject→@Environment
ios17以前は値型(struct)には @Binding、参照型(class)には @ObservedObjectを使っていた
@StateObjectと@ObservedObjectの違いは?
そもそも@StateObjectと@ObservedObjectはproperty wrapperで、データの変更を監視して、値が変更されたら、Viewを自動的に更新してくれる。
ライフサイクルが違う
@ObservedObject
親Viewのbodyが再描画されると、@ObservedObjectの値はリセットされる
@StateObject
親Viewが表示されて非表示になるまでは@StateObjectの値はリセットされない
再描画されても値はリセットされない
@Stateと@Bindingって?
@State
View内で状態を保持し、値が変わったら画面が自動で再描画される
@Binding
他のviewから状態を共有できる
親viewから子viewにデータを受け渡しできる
これに全部があった!
Discover Observation in SwiftUI
日本語訳
ViewModelに@ObservableObjectをつける
struct ContentView: View {
@ObservedObject var vm = viewModel()
var body: some View {
VStack {
Text(String(vm.book.Read))
Toggle(isOn: $vm.book.Read, label: {
Text("Read")
})
}
.padding()
}
}
final class viewModel: ObservableObject {
@Published var book = Book()
}
@Publishedがいる
ViewModelに@Observableをつける
struct ContentView: View {
@Bindable var vm = viewModel()
var body: some View {
VStack {
Text(String(vm.book.Read))
Toggle(isOn: $vm.book.Read, label: {
Text("Read")
})
}
.padding()
}
}
@Observable
final class viewModel {
var book = Book()
}
書きやすくなった!
結局@bindingと@Bindableの違いって?
@BindableはObservableプロトコルに準拠したクラスでしか使えない
値が何かによってつけるものが変わる
@Bindable→Observableプロトコルに準拠したクラス
@Binding→構造体や準拠してないクラス
ObservedObjectラッパーが@Bindableに変わった
子ビューが参照全体を別のものに変更する必要がある場合は、@Bindingを使用。オブジェクトのプロパティへのバインディングのみが必要な場合は、@Bindableを使用する
@Observableクラスのプロパティは@Bindingをサポートしてるので@Bindingも使える
@Bindable var bookTitle: String
はできない
@Binding var bookTitle: String
はできる
そもそもStringは値型(struct)なので@Bindableは使えない
struct ContentView: View {
@Bindable var vm: viewModel = viewModel()
var body: some View {
VStack {
// @Bindingを使用したビュー
// var vm: viewModel = viewModel()だと$vm.book.titleで値渡しできない
Children(book: $vm.book, bookTitle: $vm.book.title)
// 通常のビュー
Children2(book: vm.book)
// @Bindableでも大丈夫
Children3(book: vm.book)
//値を変更する
Child4(book: vm.book)
}
}
}
//Book型を@Bindingで持ってくる
struct children: View {
@Binding var book: Book
@Binding var bookTitle: String
var body: some View {
Text(book.title)
Text(bookTitle)
}
}
//Bookに@Observableがついて監視対象なので、@BindingなしでOK
struct children2: View {
var book: Book
var body: some View {
Text(book.title)
}
}
//Book型を@Bindableで持ってくる
struct children3: View {
var book: Book
var body: some View {
Text(String(book.Read))
}
}
//bookの値を変える
struct children4: View {
@Bindable var book: Book
//bindingの値を書き換えるときは@bindableいる
var body: some View {
Toggle(isOn:$book.Read, label: {
Text("Read")
})
}
}
@Observable
final class viewModel {
var book = Book()
}
@Observable
final class Book: Identifiable {
var id = UUID()
var title: String = "title"
var Read: Bool = false
}
値を書き換えるときは@bindableがいるのはなぜ?
調べ中
プロパティの変更を追跡されてないから?
双方向のデータ更新?
Bindable = インスタンスごと書き換えられない。中身の変数だけ書き換えられる
Binding = インスタンスごと書き換え可能
struct People {
name: String
age: Int
}
@Bindable var people1: People
people1 = People() //×
@Binding var people1
people1 = People() //◯
@Bindable var people: People
people.name = "jason" //◯
@Binding var people: People
people.name = "jason" //◯
@Bindable var name: String
name = "jason" //×
@Binding var name: String
name = "jason" //◯
struct CustomText() {
@Binding people: People
...
}
@Bindable var people: People = People()
CustomText($people) //×