(1) Short Answer (15 points) :

(1) Please distinguish between the following concepts

@state, @Binding, ObservableObject, @observedobject, @environmentobject

This article will teach you how to distinguish between the data state and binding methods commonly used in SwiftUI.

SwiftUI Data status and binding

plan instructions note
@State & @Binding Provides state storage within a View It should be a simple value type marked private for internal use only.
ObservableObject & @ObservedObject For state sharing across View hierarchies Handles more complex data types and triggers an interface refresh when data changes.
@EnvironmentObject For states that “jump” across multiple View hierarchies Make it easier to use ObservableObject to simplify code.

@State & @Binding

Parent view:

struct ParentView: View {
    @State private var foo: Bool = false

    var body: some View {
        VStack(spacing: 25) {
            Text("foo in Parent: \ [self.foo ? "✔ ️" : "❌")")
            ChildView(foo: $foo)}}}Copy the code

Child view:

struct ChildView: View {
    @Binding var foo: Bool

    var body: some View {
        Button("toggle foo from Child") {
            self.foo.toggle()
        }
    }
}
Copy the code

Operation effect:

@ObservedObject

Model:

class Model: ObservableObject {
    @Published var foo: Bool = false
}
Copy the code

Notice, @published is internal. In Xcode, the Playground must be public, but in Sources it must be.

import Combine

public class Model: ObservableObject {
    public let objectWillChange = PassthroughSubject<Void.Never> ()public var foo: Bool = false {
        willSet { objectWillChange.send() }
    }

    public init(a){}}Copy the code
  • let objectWillChange = PassthroughSubject<Void, Never>()Used to implementObservableObjectAgreement;
  • For every need@PublishedThe variablewillSet { objectWillChange.send() }

Parent View:

public struct ParentView: View {
   @ObservedObject var model: Model = Model(a)public var body: some View {
       VStack(spacing: 25) {
           Text("foo in Parent: \ [self.model.foo ? "✔ ️" : "❌")")
           ChildView(model: model)
       }
   }
    
    public init(a){}}Copy the code

Child View:

public struct ChildView: View {
   var model: Model

   public var body: some View {
       Button("toggle foo from Child") {
           self.model.foo.toggle()
       }
   }
    
    public init(model: Model) {
        self.model = model
    }
}
Copy the code

There’s nothing special about using class’s “pass-by-reference” feature to give the child access to the parent model.

@EnvironmentObject

ObservableObject Model:

class Model: ObservableObject {
    @Published var foo: Bool = false
}
Copy the code

Parent View:

public struct ParentView: View {
   @EnvironmentObject var model: Model

   public var body: some View {
       VStack(spacing: 25) {
           Text("foo in Parent: \ [self.model.foo ? "✔ ️" : "❌")")
           ChildView()}}public init(a){}}Copy the code

Child View:

public struct ChildView: View {
   @EnvironmentObject var model: Model

   public var body: some View {
       Button("toggle foo from Child") {
           self.model.foo.toggle()
       }
   }
    
    public init(a){}}Copy the code

Call Parent’s View:

ParentView().environmentObject(Model())
Copy the code

Use EnvironmentObject to give all children access to the parent’s Model to avoid manually passing objects layer by layer.

Complete source code implementation: SwiftUIDataStateAndBinding. Playground.

reference

SwiftUI and Combine Programming Chapter 3: Data State and Binding