无法使用 UseDefaults 的 propertyWrapper 为类型 'TextField<_>' 调用初始值设定项
Cannot invoke initializer for type 'TextField<_>' with propertyWrapper of UseDefaults
我正在处理更新 UserDefaults 中的多个值的 SwiftUI 屏幕,以允许应用保留基本设置。我正在尝试使用 Combine 和 SwiftUI,因为这是原生的 WatchOS 应用程序。
基本视图给我一个错误,我认为这与 UserDefaults 的 属性Wrapper 有关,但因为我从未使用过 属性Wrappers(或 Combine)我无法弄清楚如何解决这个问题。
这是 属性 包装器:
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 的所有密钥对。
我的class同样非常简单,由两个布尔值和一个双精度值组成
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 然后给出无法推断通用参数 'Label' 的消息。 Xcode 向 "Fix" 提供了这个,但最终结果是 TextField,这显然是不完整的,但整个程序中唯一的视图是 "ContentView",它是无效的。
问题是 TextField
的初始化程序首先将 String
作为占位符,然后是它绑定的值,因此它应该大致如下所示:
TextField("Placeholder",
value: self.$setup.someValueDouble,
formatter: currencyFormatter,
onEditingChanged: { _ in },
onCommit:{})
.keyboardType(.numberPad)
您可能想阅读有关 TextFields 和 Formatter 的更多信息,因为这似乎是一个棘手的主题。
我正在处理更新 UserDefaults 中的多个值的 SwiftUI 屏幕,以允许应用保留基本设置。我正在尝试使用 Combine 和 SwiftUI,因为这是原生的 WatchOS 应用程序。
基本视图给我一个错误,我认为这与 UserDefaults 的 属性Wrapper 有关,但因为我从未使用过 属性Wrappers(或 Combine)我无法弄清楚如何解决这个问题。
这是 属性 包装器:
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 的所有密钥对。
我的class同样非常简单,由两个布尔值和一个双精度值组成
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 然后给出无法推断通用参数 'Label' 的消息。 Xcode 向 "Fix" 提供了这个,但最终结果是 TextField,这显然是不完整的,但整个程序中唯一的视图是 "ContentView",它是无效的。
问题是 TextField
的初始化程序首先将 String
作为占位符,然后是它绑定的值,因此它应该大致如下所示:
TextField("Placeholder",
value: self.$setup.someValueDouble,
formatter: currencyFormatter,
onEditingChanged: { _ in },
onCommit:{})
.keyboardType(.numberPad)
您可能想阅读有关 TextFields 和 Formatter 的更多信息,因为这似乎是一个棘手的主题。