为了让您更好地了解如何使用ObservableObject
、@ObservedObject
、@State
和@Binding
.
前面要提的一件事 -@ObservedObject
当前在运行 iOS 13 Beta 6、7 或 8 的物理设备上运行 SwiftUI 代码时出现故障。我在此处回答了一个更详细的问题,并解释了如何将@EnvironmentObject
其用作解决方法。
我们先来看看Trade
。由于您希望Trade
在视图之间传递对象,更改该Trade
对象的属性,然后将这些更改反映在使用该Trade
对象的每个视图中,因此您需要创建Trade
一个ObservableObject
. 我已经为您的类添加了一个额外的属性,Trade
纯粹是为了说明目的,稍后我会解释。我将向您展示两种编写方法ObservableObject
- 首先是详细的方法,看看它是如何工作的,然后是简洁的方法。
import SwiftUI
import Combine
class Trade: ObservableObject {
let objectWillChange = PassthroughSubject<Void, Never>()
var name: String {
willSet {
self.objectWillChange.send()
}
}
var teamsSelected: [Int] {
willSet {
self.objectWillChange.send()
}
}
init(name: String, teamsSelected: [Int]) {
self.name = name
self.teamsSelected = teamsSelected
}
}
当我们遵守 . 时,我们ObservableObject
可以选择编写自己的. 然后,当我想发布我的对象即将发生变化时,我可以调用for和。ObservableObjectPublisher
Combine
PassthroughSubject
self.objectWillChange.send()
willSet
name
teamsSelected
但是,此代码可以显着缩短。ObservableObject
自动合成一个对象发布者,所以我们实际上不必自己声明它。我们还可以使用@Published
来声明应该发送发布者事件而不是使用self.objectWillChange.send()
in的属性willSet
。
import SwiftUI
class Trade: ObservableObject {
@Published var name: String
@Published var teamsSelected: [Int]
init(name: String, teamsSelected: [Int]) {
self.name = name
self.teamsSelected = teamsSelected
}
}
现在让我们看看你的TeamSelectView
,TeamRow
和TradeView
. 请再次记住,我进行了一些更改(并添加了一个示例TradeView
)只是为了说明一些事情。
struct TeamSelectView: View {
@ObservedObject var trade = Trade(name: "Name", teamsSelected: [])
@State var teams = [1, 1, 1, 1, 1]
var body: some View {
NavigationView{
VStack{
NavigationLink(destination: TradeView(trade: self.trade)) {
Text(self.trade.name)
}
List {
ForEach(self.teams, id: \.self) { team in
TeamRow(trade: self.trade)
}
}
Text("\(self.trade.teamsSelected.count)")
}
.navigationBarItems(trailing: Button("+", action: {
self.teams.append(1)
}))
}
}
}
struct TeamRow: View {
@ObservedObject var trade: Trade
var body: some View {
Button(action: {
self.trade.teamsSelected.append(1)
}) {
Text("Button")
}
}
}
struct TradeView: View {
@ObservedObject var trade: Trade
var body: some View {
VStack {
Text("\(self.trade.teamsSelected.count)")
TextField("Trade Name", text: self.$trade.name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
}
}
我们先来看看@State var teams
。我们@State
用于简单值类型 - Int
, String
, basic structs
- 或简单值类型的集合。@ObservedObject
用于符合 的对象,ObservableObject
我们将其用于比Int
or更复杂的数据结构String
。
您会注意到@State var teams
,我添加了一个导航栏项,teams
当按下该项时,它将向数组添加一个新项,并且由于我们List
是通过迭代该teams
数组生成的,因此我们的视图重新呈现并添加一个新项到我们List
只要按下按钮。这是一个非常基本的示例,说明您将如何使用@State
.
接下来,我们有我们的@ObservedObject var trade
. 你会注意到我并没有真正做任何与你最初不同的事情。我仍在创建我的Trade
类的一个实例并在我的视图之间传递该实例。但是由于它现在是ObservableObject
,并且我们正在使用@ObservedObject
,所以我们的视图现在都将在Trade
对象更改时接收发布者事件,并且将自动重新渲染它们的视图以反映这些更改。
我要指出的最后一件事是TextField
我在其中创建TradeView
以更新Trade
对象的name
属性。
TextField("Trade Name", text: self.$trade.name)
该$
字符表示我正在将绑定传递给文本字段。这意味着对我所做的任何更改TextField
都name
将反映在我的Trade
对象中。@Binding
当您尝试在视图之间同步状态而不传递整个对象时,您可以通过声明允许您在视图之间传递绑定的属性来自己做同样的事情。
虽然我将您更改TradeView
为 take @ObservedObject var trade
,但您可以像这样简单地将teamsSelected
您的交易视图作为绑定传递TradeView(teamsSelected: self.$trade.teamsSelected)
- 只要您TradeView
接受绑定。要配置您TradeView
接受绑定,您所要做的就是像这样声明您的teamsSelected
属性TradeView
:
@Binding var teamsSelected: [Team]
最后,如果您在使用物理设备时遇到问题,您可以在此处@ObservedObject
参考我的回答,以了解如何将其用作解决方法。@EnvironmentObject