2

我试图让用户控制相机硬件的设置,因此有一个设置视图和一个不同的视图,他们可以通过单击按钮选择要应用的预设。当导航回设置视图(通过 TabView)时,我希望根据单击的预设按钮显示值。但是,我发现除非单击两次按钮,否则某些UserDefault 存储的值不会被更改。

正确更新的 UserDefaults 和非工作的用户默认值之间的差异:
- 在 TextField 的设置视图中显示(并且能够更改)非工作(直到第二次点击)值,而正确工作的值被显示(并且能够要更改)由滑块。
- 非工作值默认为 Ints 并更新为 Ints,而其他值为 Floats。

我尝试过的事情:
UserDefaults.standard.setValue(values[0], forKey: "exposureISO")
UserDefaults.standard.set(Int(values[0], forKey: "exposureISO")
UserDefaults.standard.synchronize()

这是我的代码,希望能证明问题可能出在哪里:\

import SwiftUI
import Combine

struct Settings: View {

    let minISO = UserDefaults.standard.integer(forKey: "minISO")
    let maxISO = UserDefaults.standard.integer(forKey: "maxISO")
    let maxGain = UserDefaults.standard.integer(forKey: "maxGain")

    @AppStorage("exposureISO") var exposureISO = DefaultSettings.exposureISO
    @State private var enteredExposureISO: String = ""
    @AppStorage("redGain") var redGain = DefaultSettings.redGain

    var body: some View {
        ScrollView {
            VStack {
                TextField("", text: self.$enteredExposureISO)
                    .onReceive(Just(enteredExposureISO)) { typedValue in
                        if let newValue = Int(typedValue) {
                            if (newValue >= Int(minISO)) && (newValue <= Int(maxISO)) {
                                exposureISO = newValue
                            }
                        }
                    }
                .textFieldStyle(.roundedBorder)
                .padding()
                .onAppear(perform:{self.enteredExposureISO = "\(exposureISO)"})

                Slider(
                    value: $redGain,
                    in: 1...Double(maxGain),
                    step: 0.1
                ) {
                    Text("red Gain")
                } minimumValueLabel: {
                    Text("1")
                } maximumValueLabel: {
                    Text("4")
                }
                .padding([.leading, .trailing, .bottom])
            }
        }
    }
}

enum DefaultSettings {
    static let exposureISO = 300
    static let redGain = 2.0
}

struct JobView: View {

    @ObservedObject var job: Job //does this need to be observed...?

    var body: some View {
        VStack {
            Text("Settings").fontWeight(.medium)
            Text(job.settings ?? "settings not found")
                .multilineTextAlignment(.trailing)
        
            Button(action: applySettings) {
                Text("Apply these settings")
            }
        }
    }

    func applySettings() {
    //parse job.settings and apply the values to the camera hardware
        var value = ""
        var values : [Float] = []
        for char in job.settings! {
            if Int(String(char)) != nil || char == "." {
                value.append(char)
            } else if char == "\n" {
                values.append(Float(value)!)
                value = ""
            }
        }
        UserDefaults.standard.set(values[0], forKey: "exposureISO")
        UserDefaults.standard.set(values[1], forKey: "redGain")
    }
}

如果按钮被点击两次,我发现 UserDefaults 被正确设置是最奇怪的。我感谢诊断问题以及如何解决问题的任何帮助!

编辑

就像评论中描述的和 ChrisR 建议的那样,我改为.onReceive破解.onSubmit/解决问题,但我还不完全理解为什么在Just(...)点击按钮时发布者会发出。这是修复:\

TextField("", text: self.$enteredExposureISO)
    .onSubmit {
        if let newValue = Int(enteredExposureISO) {
            if (newValue >= Int(minISO)) && (newValue <= Int(maxISO)) {
                print("new value \(newValue)")
                exposureISO = newValue
            }
        }
    }
    .textFieldStyle(.roundedBorder)
    .padding()
    .onAppear(perform:{self.enteredExposureISO = "\(exposureISO)"})
4

0 回答 0