我有一个看起来像这样的模型类型:
enum State {
case loading
case loaded([String])
case failed(Error)
var strings: [String]? {
switch self {
case .loaded(let strings): return strings
default: return nil
}
}
}
class MyApi: ObservableObject {
private(set) var state: State = .loading
func fetch() {
... some time later ...
self.state = .loaded(["Hello", "World"])
}
}
我正在尝试使用它来驱动SwiftUI视图。
struct WordListView: View {
@EnvironmentObject var api: MyApi
var body: some View {
ZStack {
List($api.state.strings) {
Text($0)
}
}
}
}
正是在这里我的假设失败了。我正在尝试获取要加载的List
中呈现的字符串的列表,但无法编译。
编译器错误为Generic parameter 'Subject' could not be inferred
,经过一番谷歌搜索后得知绑定是双向的,因此无法同时读取我的private(set)
和正在读取的State枚举上的var -仅。
这似乎没有任何意义-视图无法告诉api是否正在加载,这绝对应该是单向数据流!
我想我的问题是
或
答案 0 :(得分:4)
您实际上不需要绑定。
决定是否需要绑定的一种直观方法是询问:
此视图是否需要修改传递的值?
在您的情况下,答案是否定的。 List
不需要修改api.state
(例如,与文本字段或滑块相反),它只需要在任何给定时刻使用其当前值即可。这就是@State
对于但是的意思,因为状态不是视图的属于(请记住,Apple表示每个状态必须对视图私有) ),您正确地使用了某种形式的ObservableObject
(通过环境)。
最后遗失的部分是用@Published
标记应触发更新的任何属性,这很方便触发objectWillChange
信号并指示任何观察视图重新计算其主体。
所以,像这样的事情会完成:
class MyApi: ObservableObject {
@Published private(set) var state: State = .loading
func fetch() {
self.state = .loaded(["Hello", "World"])
}
}
struct WordListView: View {
@EnvironmentObject var api: MyApi
var body: some View {
ZStack {
List(api.state.strings ?? [], id: \.self) {
Text($0)
}
}
}
}