自定义 属性 包装器无法准确反映 SwiftUI 中我的 TextField 的状态,知道为什么吗?

Custom property wrapper not accurately reflecting the state of my TextField in SwiftUI, any idea why?

我已经创建了一个 属性 包装器,我想在其中插入一些逻辑,并且“设置”值正在做正确的事情,但是文本字段没有更新为所有大写文本。文本字段不应该显示所有大写文本还是我误解了这是如何工作的?

这也是一个人为的例子,我的最终目标是在 属性 包装器中插入更多的逻辑,我只是​​使用大写的例子来让它工作。我在整个互联网上进行了搜索,但没有找到可行的解决方案。

import SwiftUI
import Combine

struct ContentView: View {
    @StateObject var vm = FormDataViewModel()

    var body: some View {
        Form {
            TextField("Name", text: $vm.name)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

class FormDataViewModel: ObservableObject {
    @Capitalized var name: String = ""
}

@propertyWrapper
public class Capitalized {
    @Published var value: String

    public var wrappedValue: String {
        get { value }
        set { value = newValue.uppercased() } //Printing this shows all caps
    }

    public var projectedValue: AnyPublisher<String, Never> {
        return $value
            .eraseToAnyPublisher()
    }

    public init(wrappedValue: String) {
        value = wrappedValue
    }
}

SwiftUI 监视 @StateObject@ObservedObject 中的 @Published 属性并触发 UI 更新它们的变化。

但它并没有深入ObservableObject。您的 FormDataViewModel 没有任何 @Published 属性。


您可以做的一件事是模拟 @Published 对值变化的影响。

class FormDataViewModel: ObservableObject {
    @Capitalized var name: String = ""
    private var nameObserver: AnyCancellable?

    init() {
        nameObserver = _name.$value.sink {_ in
            self.objectWillChange.send()
        }
    }
}

请尝试。

这可以用看起来更简单、更可靠的标准 @Published 来完成。

这是一个解决方案。测试 Xcode 12 / iOS 14.

class FormDataViewModel: ObservableObject {
    @Published var name: String = "" {
        didSet {
            let capitalized = name.uppercased()
            if name != capitalized {
                name = capitalized
                objectWillChange.send()
            }
        }
    }
}