来自 ObservableObject 的绑定值

Binding value from an ObservableObject

目标:

我有一个模型是 ObservableObject。它有一个 Bool 属性,我想用这个 Bool 属性 来初始化一个 @Binding 变量。

问题:

  1. 如何将 @ObservableObject 转换为 @Binding
  2. 创建 @State 是初始化 @Binding 的唯一方法吗?

注:

代码:

import SwiftUI
import Combine
import SwiftUI
import PlaygroundSupport

class Car : ObservableObject {

    @Published var isReadyForSale = true
}

struct SaleButton : View {

    @Binding var isOn : Bool

    var body: some View {

        Button(action: {

            self.isOn.toggle()
        }) {
            Text(isOn ? "On" : "Off")
        }
    }
}

let car = Car()

//How to convert an ObservableObject to a Binding
//Is creating an ObservedObject or EnvironmentObject the only way to handle a Observable Object ?

let button = SaleButton(isOn: car.isReadyForSale) //Throws a compilation error and rightly so, but how to pass it as a Binding variable ?

PlaygroundPage.current.setLiveView(button)

Binding变量可以通过以下方式创建:

  1. @State 变量的预测值提供 Binding<Value>
  2. @ObservedObject 变量的投影值提供了一个包装器,您可以从中获取 Binding<Subject> 的所有属性
  3. 第 2 点也适用于 @EnvironmentObject
  4. 您可以通过为 getter 和 setter 传递闭包来创建绑定变量,如下所示:
let button = SaleButton(isOn: .init(get: { car.isReadyForSale },
                                    set: { car.isReadyForSale = [=10=]} ))

注:

  • 正如@nayem 指出的那样,您需要 @State / @ObservedObject / @EnvironmentObject / @StateObject(在 SwiftUI 2.0 中添加) 在 SwiftUI 的视图中自动检测更改。
  • 可以使用 $ 前缀方便地访问投影值。

backup

struct ContentView: View {
    @EnvironmentObject var car: Car

    var body: some View {
        SaleButton(isOn: self.$car.isReadyForSale)
    }
}

class Car: ObservableObject {
    @Published var isReadyForSale = true
}

struct SaleButton: View {
    @Binding var isOn: Bool

    var body: some View {
        Button(action: {
            self.isOn.toggle()
        }) {
            Text(isOn ? "On" : "Off")
        }
    }
}

确保您的 SceneDelegate 中包含以下内容:

// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
    .environmentObject(Car())
  1. 您有多种选择来观察ObservableObject。如果要与对象的状态同步,那么观察stateful对象的状态是免不了的。从选项中,最常见的是:

    • @State
    • @ObservedObject
    • @EnvironmentObject

这取决于您,哪一个适合您的用例。

  1. 没有。但是你需要有一个对象,可以观察到在任何时间点对该对象所做的任何更改。

在现实中,你会遇到这样的事情:

class Car: ObservableObject {
    @Published var isReadyForSale = true
}

struct ContentView: View {

    // It's upto you whether you want to have other type 
    // such as @State or @ObservedObject
    @EnvironmentObject var car: Car

    var body: some View {
        SaleButton(isOn: $car.isReadyForSale)
    }

}

struct SaleButton: View {
    @Binding var isOn: Bool
    var body: some View {
        Button(action: {
            self.isOn.toggle()
        }) {
            Text(isOn ? "Off" : "On")
        }
    }
}

如果您准备好 @EnvironmentObject,您将初始化您的视图:

let contentView = ContentView().environmentObject(Car())

在我的例子中,我使用 .constant(viewModel) 将 viewModel 传递给 ListView @Binding var viewModel

示例

struct CoursesView: View {
    
    @StateObject var viewModel = CoursesViewModel()
    
    var body: some View {
        
        ZStack {
            ListView(viewModel: .constant(viewModel))
            ProgressView().opacity(viewModel.isShowing)
        }
    }
}

struct ListView: View {
    
    @Binding var viewModel: CoursesViewModel
    
    var body: some View {
        
        List {
            ForEach(viewModel.courses, id: \.id) { course in
                Text(couse.imageUrl)
            }
        }
    }
}