首页 > 解决方案 > 无法使用 UseDefaults 的 propertyWrapper 调用类型“TextField<_>”的初始化程序

问题描述

我正在开发一个更新 UserDefaults 中的多个值的 SwiftUI 屏幕,以允许应用程序保留基本设置。我正在尝试使用 Combine 和 SwiftUI,因为这是一个原生 WatchOS 应用程序。

基本视图给了我一个错误,我认为这与 UserDefaults 的 propertyWrapper 有关,但由于我从未使用过 propertyWrapper(或就此而言的组合),我无法弄清楚如何解决这个问题。

这是属性包装器:

import Foundation

@propertyWrapper
struct UserDefault<T> {
    let key: String
    let defaultValue: T

    init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            UserDefaults(suiteName: "group.com.my.app")!.value(forKey: key) as? T ?? defaultValue
        } set {
            UserDefaults(suiteName: "group.com.my.app")!.set(newValue, forKey: key)
        }
    }
}

如您所见,它包装了 UserDefaults 的所有密钥对。

我的类同样非常简单,由两个 bool 和一个 double

import SwiftUI
import Foundation
import Combine

class Setup: ObservableObject {

    private var notificationSubscription: AnyCancellable?

    let objectWillChange = PassthroughSubject<Setup,Never>()

    @UserDefault("keyOpt1Enabled", defaultValue: false)
    var opt1Enabled: Bool {
        willSet{
            objectWillChange.send(self)
        }
    }

    @UserDefault("keyOpt2Enabled", defaultValue: false)
    var opt2Enabled: Bool {
        willSet{
            objectWillChange.send(self)
        }
    }

    @UserDefault("keyValueDouble", defaultValue: Double(0.00))
    var someValueDouble: Double {
        willSet{
            objectWillChange.send(self)
        }

    }
    init() {

        notificationSubscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { _ in
                   self.objectWillChange.send(self)
        }
    }
}

问题是在 SwiftUI 中我使用 TextField 来允许输入和更新双精度值


    @ObservedObject var setup: Setup = Setup()

    private var currencyFormatter: NumberFormatter = {
        let f = NumberFormatter()
        f.numberStyle = .currency
        return f
    }()


    var body: some View {
        ScrollView{
            HStack{
                TextField(self.$setup.someValueDouble,
                          formatter: currencyFormatter,
                          placeholder: "0.00",
                          onEditingChanged: {_ in
                            print("editing changed")
                          },
                          onCommit: {
                            print("updated")
                            }
                )
            }

            HStack{
                Button(action: {
                    self.setup.opt1Enabled = false
                    self.setup.opt2Enabled = true
                } ) {
                    Text(verbatim: "Opt 1")
                        .font(Font.system(size: 16, design: Font.Design.rounded))
                }
                .background(setup.opt1Enabled ? Color.blue : Color.gray)
                .disabled(self.setup.opt1Enabled)
                .cornerRadius(5)

                Button(action: {
                    self.setup.opt1Enabled = true
                    self.setup.opt2Enabled = false
                }) {
                    Text(verbatim: "Opt 2")
                }
                .background(setup.opt2Enabled ? Color.blue : Color.gray)
                .disabled(self.setup.opt2Enabled)
            }
        }
    }
}

然后,TextField 给出无法推断通用参数“标签”的消息。Xcode 提供“修复”此问题,但最终结果是 TextField,这显然是不完整的,但整个程序中唯一的视图是“ContentView”,它是无效的。

标签: propertieswrapperswiftuicombine

解决方案


问题是TextField' 的初始化程序首先将 aString作为占位符,然后将其绑定到的值,因此它应该大致如下所示:

 TextField("Placeholder",
           value: self.$setup.someValueDouble,
           formatter: currencyFormatter,
           onEditingChanged: { _ in },
           onCommit:{})
     .keyboardType(.numberPad)

您可能想了解更多有关 TextFields 和 Formatter 的信息,因为它似乎是一个棘手的主题。


推荐阅读