【问题标题】:Save to UserDefaults Getting Called 19 Times保存到 UserDefaults 被调用 19 次
【发布时间】:2020-10-13 22:19:01
【问题描述】:

嘿,由于状态更改或保存操作,某些 SwiftUI 代码被多次调用是否正常?此代码是一个选择器,有 4 个选项可供选择。然后通过方法 saveBase 将选定的选项保存到 UserDefaults。我在方法中添加了一条打印语句以确认我的值正确到达,并发现每次对选择器进行更改时,该方法都会被调用 19 次。该代码可以正常保存和恢复baseCurr。作为具有汇编和 C 经验的固件工程师,我认为这是相当有缺陷的代码,但我不太确定。有什么想法吗?

class UserData: ObservableObject {
    
    @Published var baseCurr: Int = 0

    func saveBase() -> () {
        let defaults = UserDefaults.standard
        defaults.set(self.baseCurr, forKey: "base")
        
        print("  base Curr = \(self.baseCurr)")
    }
}
struct aboutView: View {
    
    @EnvironmentObject var userData: UserData
    
    let baseCurrs = ["block A", "block B","block C","block D"]
    
    var body: some View {
        
        Form {
            VStack (alignment: .leading) {
                Text("Select Base")
                
                Picker(selection: $userData.baseCurr, label: Text("Curr >")) {
                    ForEach(0 ..< baseCurrs.count) {
                        Text( baseCurrs[$0])
                    }
                    .onChange(of: userData.baseCurr) { newValue in
                        userData.saveBase()
                    }
                }
            }
            .padding()
        }
        .navigationBarTitle("About", displayMode: .inline) 
    }
}

【问题讨论】:

  • .onAppear 附加到PickerVStack 而不是ForEach

标签: swift swiftui ios14 userdefaults


【解决方案1】:

正如 NewDev 在 cmets 中指出的那样,您需要将 onChange 修饰符附加到单个视图(如 PickerVStack)而不是 ForEach

但是,您可以通过完全删除 .onChange 修饰符和 saveBase() 函数来使代码更简洁。

您可以将didSet 添加到baseCurr 属性中,以便在设置时保存该值:

class UserData: ObservableObject {
    @Published var baseCurr: Int = UserDefaults.standard.integer(forKey: "base") {
        didSet {
            UserDefaults.standard.set(baseCurr, forKey: "base")
            print("  base Curr = \(baseCurr)")
        }
    }
}

现在你不需要onChange

Picker(selection: $userData.baseCurr, label: Text("Curr >")) {
    ForEach(0 ..< baseCurrs.count) {
        Text(baseCurrs[$0])
    }
}

【讨论】:

  • 我没有展示它,但是 UserData init 方法从 UserDefaults 初始化 baseCurr。那么你认为 iPhone 中缺少信号(输入)去抖动吗?嘈杂的选择器导致 onChange 多次调用 save 方法?
  • @GalenSmith 您只是不能将onChange 附加到 ForEach。请从我的回答中查看UserData 版本。
  • 我摆脱了 onChange 并将您建议的更改添加到 UserData。它工作得很好,只更新一次 baseCurr!
  • @GalenSmith 很高兴它对您有所帮助 :) 如果您觉得我的回答解决了您的问题,您可以接受(和/或投票) - 请参阅 What should I do when someone answers my question?
【解决方案2】:

您的.onChange 被称为baseCurrs.count 次,因为您将它附加到动态ForEach 容器,所以.onChange 实际上附加到每个Text(baseCurrs[$0]),所以要解决这个问题,保留您的代码,它只需要移动.onChange动态容器外,喜欢

VStack (alignment: .leading) {
    Text("Select Base")
    
    Picker(selection: $userData.baseCurr, label: Text("Curr >")) {
        ForEach(0 ..< baseCurrs.count) {
            Text(baseCurrs[$0])
        }
    }
}
.onChange(of: userData.baseCurr) { newValue in   // for eg. here !!
    userData.saveBase()
}
.padding()

【讨论】:

    猜你喜欢
    • 2017-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2017-05-09
    相关资源
    最近更新 更多