【问题标题】:How to re-render UI in response to computed property buried in a nested class?如何重新渲染 UI 以响应埋在嵌套类中的计算属性?
【发布时间】:2021-12-22 21:57:38
【问题描述】:

我不清楚如何将以下计算属性的输出组合到 UI。

var isComplete: Bool {
    Set([.givenName, .familyName]).isSubset(of: elements)
}

如果上述更改,我基本上希望用户界面更新。我将如何使用 Combine 来做到这一点?

反应式编程要求我现在向后思考,我在考虑模型 >> UI 时遇到了麻烦。

这是上下文中的代码。

struct EditPersonView: View {
    
    let model: ViewModel
            
    private var captionView: some View {
        HStack {
        /*
          stuff
        */
            if submitted && model.name.isComplete {
                Spacer()
                Text("select".localizedCapitalized) + Text(" ") + Text("save") + Text(" ") + Text("????")
            }
        }
    }

    var body: some View {
    /*
    stuff - including captionView
    */
    }
}

extension EditPersonView {
    
    final class ViewModel {
        
        let name: PersonName
        
        init(person: Person) {
            self.name = PersonName(for: person)
        }
    }
}

extension EditPersonView.ViewModel {
    
    final class PersonName {
        
        let person: Person
        
        private let formatter = PersonNameComponentsFormatter()
        
        init(for person: Person) {
            self.person = person
        }
        
        var text: String {
            get { person.name ?? "" }
            set { person.name = newValue }
        }
        
        private var components: PersonNameComponents? {
            formatter.personNameComponents(from: text)
        }
        
        var givenName: String? {
            components?.givenName
        }
        
        var familyName: String? {
            components?.familyName
        }
        
        private func isValid(component: String?) -> Bool {
            if let name = component, name.count > 1 {
                return true
            }
            return false
        }
        
        var elements: Set<Elements> {
            var collection = Set<Elements>()
            if isValid(component: givenName) { collection.insert(.givenName) }
            if isValid(component: familyName) { collection.insert(.familyName) }
            return collection
        }
        
        var isComplete: Bool {
            Set([.givenName, .familyName]).isSubset(of: elements)
        }
    }
}

extension EditPersonView.ViewModel.PersonName {
    
    enum Elements {
        case givenName, familyName
    }
}

【问题讨论】:

  • 为什么不使用 ObservableObject 作为类和 @Published var isComplete ?

标签: swiftui combine


【解决方案1】:

以下是我想出的。

序列的根是textPublisher。这将从发送到text 的值开始序列。

didSet 将文本发送到序列,并像原始代码一样将其保存在人名中。

isComplete 成为发布者,根据组件是否有效发送truefalsemap 运算符链每个都通过原始代码中的一个计算步骤获取值。我认为您可以轻松地将其简化为单个map。 (或将计算过滤到具有有意义名称的函数中,并将函数替换为闭包)

外部Subscriber 可以订阅isComplete 并在发出true 值时做出响应。

final class PersonName {
    var person: Person

    private let formatter = PersonNameComponentsFormatter()

    let textPublisher = PassthroughSubject<String, Never>()
    var text: String {
        get { person.name ?? "" }
        set { textPublisher.send(newValue); person.name = newValue }
    }

    var isComplete : AnyPublisher<Bool, Never>!

    init(for person: Person) {
        self.person = person

        isComplete = textPublisher
            .map{ self.formatter.personNameComponents(from: $0) }
            .map{ (components: PersonNameComponents?) -> Set<Elements> in
                var collection = Set<Elements>()

                if let components = components {
                    if self.isValid(component: components.givenName) { collection.insert(.givenName) }
                    if self.isValid(component: components.familyName) { collection.insert(.familyName) }
                }

                return collection
            }
            .map { Set([Elements.givenName, Elements.familyName]).isSubset(of: $0) }
            .eraseToAnyPublisher()
    }

    private func isValid(component: String?) -> Bool {
        if let name = component, name.count > 1 {
            return true
        }
        return false
    }
}

【讨论】:

    猜你喜欢
    • 2021-10-04
    • 2021-05-10
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-16
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多