【问题标题】:SwiftUI Binding to Computed Property?SwiftUI 绑定到计算属性?
【发布时间】:2020-02-20 06:45:29
【问题描述】:

我有两个类,一个是显示来自我的数据源的信息的 ContentView。数据源是我的 CharacterRepository。

我现在正在努力确保我的 CharacterRepository 中始终有一个排序列表。

这是我目前的代码:

class CharacterRepository: ObservableObject {
    @Published public var characters = [Character(name: "Nott the Brave",
                                                  initiative: 23,
                                                  isActive: false),
                                        Character(name: "Caduceus Clay",
                                                  initiative: 2,
                                                  isActive: false),
                                        ...]
    ...
}

struct InitiativeTrackerScreen: View {
    @EnvironmentObject var characterRepository: CharacterRepository

    var body: some View {
        NavigationView {
            VStack {
                List {
                    ForEach(characterRepository.characters) { entry in
                        CharacterListElement(character: entry)
                    }
    ...

现在我的预期方法是将字符变量转换为计算属性,该属性在每次执行 get 时运行“排序依据”函数。不幸的是,在 SwiftUI 中还不能绑定到计算属性(不确定,会不会?)。

有人可以帮我解决这个问题吗?我不想每次发生变化时都回到旧的排序和重绘方法。这不是我使用带有 ist sweet 绑定的 SwiftUI 的原因。

【问题讨论】:

    标签: ios swift data-binding swiftui


    【解决方案1】:

    我认为在属性 getter 中对数据进行排序可能是不必要的开销。

    简单(且注重性能)的解决方案是在数据发生变化时对其进行排序,然后更新 @Published 非计算属性并绑定到该属性:

    class CharacterRepository: ObservableObject {
        func updateCharacters(_ characters: [Character]) {
           self.characters = characters.sorted() // or whatever sorting strategy you need...
        }
    
        @Published public var characters = [Character(name: "Nott the Brave",
                                                      initiative: 23,
                                                      isActive: false),
                                            Character(name: "Caduceus Clay",
                                                      initiative: 2,
                                                      isActive: false),
                                            ...]
        ...
    }
    

    如果您更愿意以牺牲性能为代价成为 über-purist,那么您可以手动创建一个 Binding - 如下所示:

    class CharacterRepository: ObservableObject {
       let sortedCharacters: Binding<[Character]>
       ...
    
    
       init() { 
          self.sortedCharacters = .init(get: { return characters.sorted() }, set: { self.characters = $0 })
       }
    
       ...
    }
    

    【讨论】:

    • 感谢您的回复!这实际上是我的想法,但这意味着我将在我的数据源内部拥有一个视图状态,这不是一个很好的关注点分离。但老实说,我认为这可能是我目前最好的选择。这意味着,如果对数组进行了某些操作,我将始终需要确保对数组进行排序。第二个目前正在给我麦角,因为我在所有成员初始化之前使用 self 。但这是可以解决的。 :) 我会尝试两种方法!非常感谢!
    • @bob_mosh 不客气。我强烈推荐第一种方法 - 更新排序总是比每次视图请求数据时排序要快得多。
    • 是的,这是真的。这样我就可以决定何时运行代码,而不是每次使用数据时都运行它。现在对我来说不是一个大问题,但将来可能会。
    • 我现在选择了第一个选项。不得不在这里和那里添加几个电话,但就像一个魅力。 :) 但是它不是反应式的。
    【解决方案2】:

    我喜欢通过相关问题来回答。你需要什么绑定到计算属性?

    class CharacterRepository: ObservableObject {
        @Published public var characters = [Character(name: "Nott the Brave",
                                                      initiative: 23,
                                                      isActive: false),
                                            Character(name: "Caduceus Clay",
                                                      initiative: 2,
                                                      isActive: false),
                                            ...]
        ...
        var sorted: [Character] {
            characters.sorted()
        }
    }
    

    就是你所需要的。

    【讨论】:

    • 例如捕获输入的数据并在将其添加到数组之前进行验证检查,或者例如根据处理排序的不同变量返回排序列表。计算属性将非常适合。
    • 计算属性仅是 getter。因此,根据定义,对它具有约束力是不可能的。你可以返回一些兑现的值,或者你想要的任何东西,比如说“预先计算”的排序值,这些值在一些后台任务中排序......没有必要将它包装到任何 @Published 属性包装器中,因为如果存储数组更改(您添加或修改一些值),SwiftUI 被告知。
    • 如果你想返回不同的结果,你必须包装(并从 UI 修改)排序过程的参数,而不是结果本身。
    • 是的,这就是我现在正在做的事情。我觉得拥有一个根据我的状态自动排序的数据源以进行排序可能是一种处理事情的聪明方法,但似乎将这两件事分开并不是最聪明的方法。 :) 感谢您的输入!这真的很有帮助!
    猜你喜欢
    • 2020-10-24
    • 2018-02-12
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    • 2014-09-06
    • 1970-01-01
    • 2020-10-25
    相关资源
    最近更新 更多