在 SwiftUI 中绑定到只读 属性
Binding to a read-only property in SwiftUI
我的模型类型如下所示:
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([=12=])
}
}
}
}
我的假设就在这里失败了。我正在尝试获取要在我的 List
中呈现的字符串列表,但无法编译。
编译器错误是 Generic parameter 'Subject' could not be inferred
,经过一些谷歌搜索后告诉我绑定是双向的,所以不能同时使用我的 private(set)
和 State 枚举上的 var只读。
这似乎没有任何意义 - 视图无法告诉 api 它是否正在加载,这绝对应该是一种单向数据流!
我想我的问题是
- 有没有一种方法可以在 Swift 中获得单向绑定UI - 即某些 UI 将根据无法更改的值进行更新。
或
- 我应该如何构建这段代码!我编写代码的风格很可能不适用于 SwiftUI,但我在网上看到的所有教程都巧妙地忽略了加载/错误状态等内容。
您实际上不需要对此进行绑定。
决定是否需要绑定的一种直观方法是询问:
Does this view need to modify the passed value ?
在你的情况下,答案是否定的。 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([=10=])
}
}
}
}
我的模型类型如下所示:
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([=12=])
}
}
}
}
我的假设就在这里失败了。我正在尝试获取要在我的 List
中呈现的字符串列表,但无法编译。
编译器错误是 Generic parameter 'Subject' could not be inferred
,经过一些谷歌搜索后告诉我绑定是双向的,所以不能同时使用我的 private(set)
和 State 枚举上的 var只读。
这似乎没有任何意义 - 视图无法告诉 api 它是否正在加载,这绝对应该是一种单向数据流!
我想我的问题是
- 有没有一种方法可以在 Swift 中获得单向绑定UI - 即某些 UI 将根据无法更改的值进行更新。
或
- 我应该如何构建这段代码!我编写代码的风格很可能不适用于 SwiftUI,但我在网上看到的所有教程都巧妙地忽略了加载/错误状态等内容。
您实际上不需要对此进行绑定。
决定是否需要绑定的一种直观方法是询问:
Does this view need to modify the passed value ?
在你的情况下,答案是否定的。 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([=10=])
}
}
}
}