Невозможно вызвать инициализатор для типа 'TextField <_>' с помощью propertyWrapper of UseDefaults - PullRequest
0 голосов
/ 06 октября 2019

Я работаю над экраном SwiftUI, который обновляет несколько значений в UserDefaults, чтобы приложение сохраняло основные настройки. Я пытаюсь использовать Combine и SwiftUI, так как это родное приложение WatchOS.

Базовое представление дает мне ошибку, которая, как мне кажется, связана с propertyWrapper для UserDefaults, но так как я никогда не работал сpropertyWrappers (или 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)
        }
    }
}

Как вы можете видеть, она охватывает все пары ключей для пользовательских значений.

Мой класс аналогично очень прост, состоящий из двухbools and 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», который недопустим.

1 Ответ

1 голос
/ 06 октября 2019

Проблема в том, что инициализатор TextField берет сначала String в качестве заполнителя, а затем значение, к которому он привязан, поэтому он должен выглядеть примерно так:

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

Возможно, выЯ хочу узнать больше о TextFields и Formatter, потому что это сложный вопрос.

...