これらのプロパティラッパーはすべて、とをSwiftUIに伝えます。重要な分かれ目は、(、)と(、、)、そしてそのオブジェクトの生存期間の責任を誰が負うかです。
@State@Binding@StateObject@ObservedObject@EnvironmentObject// Value state OWNED by this view
struct Toggle: View {
@State private var isOn = false // local source of truth
var body: some View {
Switch(isOn: $isOn) // $ makes a Binding
}
}
// A two-way reference to state owned ELSEWHERE
struct Switch: View {
@Binding var isOn: Bool // no ownership; reads+writes parent
var body: some View { Button("\(isOn)") { isOn.toggle() } }
}
final class CartModel: ObservableObject {
@Published var items: [Item] = [] // change => views re-render
}
struct CartScreen: View {
@StateObject private var model = CartModel() // OWNS: created once, survives re-renders
var body: some View { CartList(model: model) }
}
struct CartList: View {
@ObservedObject var model: CartModel // observes; owned by a parent
var body: some View { Text("\(model.items.count)") }
}
| ラッパー | 型 | 所有権 | 使う場面 |
|---|---|---|---|
@State | 値型 | このビュー | 単純なローカル状態 |
@Binding | 値型 | 親 | 子が親の状態を編集する |
@StateObject | 参照型 | このビュー(一度だけ生成) | ビューがモデルを生成する |
@ObservedObject | 参照型 | 別の場所 | モデルが渡される |
@EnvironmentObject | 参照型 | 祖先 | ツリーの深いところで共有される |
@StateObject と @ObservedObject の違いは典型的な罠です。 @ObservedObject var m = Model() でモデルを生成すると、再描画のたびに再インスタンス化され、静かに状態を失います。ビューがオブジェクトを生成する場所では必ず @StateObject を使ってください。@EnvironmentObject は、祖先が .environmentObject(...) で注入していない場合、実行時にクラッシュします。間違ったラッパーを選ぶことは、SwiftUIの状態バグの最大の原因です。値のちらつき、スクロール時のリセット、決して更新されないビューなどです。面接官がこれを尋ねるのは、@StateObject と @ObservedObject の答えが、あなたがSwiftUIの所有権モデルを理解しているかを即座に明らかにするからです。
ジュニアからシニアまで、詳細な回答付きのIT面接質問ライブラリ。
寄付する