【问题标题】:Binding to a read-only property in SwiftUI绑定到 SwiftUI 中的只读属性
【发布时间】:2020-04-25 08:28:21
【问题描述】:

我有一个看起来像这样的模型类型:

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 它是否正在加载,这绝对应该是单向数据流!

我想我的问题是要么

  1. 有没有办法在 SwiftUI 中获得单向绑定 - 即某些 UI 将根据无法更改的值进行更新。

  1. 我应该如何构建这段代码!很可能我编写的代码风格不适用于 SwiftUI,但我在网上看到的所有教程都巧妙地忽略了加载/错误状态等内容。

【问题讨论】:

  • 列表不需要绑定,为什么你使用List($api.state.strings) 而不是,我希望,List(api.state.strings)
  • 因为 (a) 我是 SwiftUI 的新手,并且 (b) 当我这样做时,它并没有更新 UI。应该这样做吗?
  • 我愿意,并将state 设为@Published 以更新视图
  • @Asperi 你应该把这个作为答案,所以我可以勾选它:) 我没有意识到对可观察对象的任何更改都会触发重绘,即使它们不是绑定。现在完美运行,谢谢!

标签: swift swiftui combine


【解决方案1】:

您实际上不需要为此绑定。

决定是否需要绑定的直观方法是询问:

这个视图需要修改传入的值吗?

在您的情况下,答案是否定的。 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)
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 2010-11-19
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多