【问题标题】:How to use @AppStorage in ViewModel with custom types and @Published?如何在 ViewModel 中使用带有自定义类型和 @Published 的 @AppStorage?
【发布时间】:2021-09-16 10:15:16
【问题描述】:

如何在我的 ViewModel 中使用 @AppStorage 来保存一组自定义类型?如何将@AppStorage 与@Published 属性一起使用?

这是我的示例代码:

型号

struct MyModel: Hashable, Codable {
    var text: String
    var number: Int
}

查看模型

class ViewModel: ObservableObject {

    @Published private(set) var myModels = [MyModel]()
    @Published private(set) var subscribedMyModels = [MyModel]() // TODO: sync this with AppStorage

    func fetchMyModels() {
        myModels = [
            MyModel(text: "Setting", number: 1),
            MyModel(text: "Setting", number: 2),
            MyModel(text: "Setting", number: 3),
            MyModel(text: "Setting", number: 4),
            MyModel(text: "Setting", number: 5),
            MyModel(text: "Setting", number: 6),
            MyModel(text: "Setting", number: 7),
            MyModel(text: "Setting", number: 8)
        ]
    }

    func toggleSubscription(for myModel: MyModel) {
        if subscribedMyModels.contains(myModel) {
            subscribedMyModels.removeAll(where: { $0 == myModel } )
        } else {
            subscribedMyModels.append(myModel)
        }
    }

}

查看

struct ContentView: View {

    @StateObject var viewModel = ViewModel()
    @AppStorage(wrappedValue: false, "settings0") private var settings0

    var body: some View {
        List {

            Section(header: Text("Some Settings")) {
                Toggle(isOn: $settings0, label: {
                    Text("Setting 0")
                })
            }
            Section(header: Text("Some other Settings")) {
                ForEach(viewModel.myModels, id: \.self) { myModel in
                    Button(action: {
                        viewModel.toggleSubscription(for: myModel)
                    }, label: {
                        HStack {
                            HStack {
                                Text(myModel.text)
                                Text(String(myModel.number))
                            }
                            Spacer()

                            if viewModel.subscribedMyModels.contains(myModel) {
                                Image(systemName: "checkmark.circle.fill")
                            } else {
                                Image(systemName: "circle")
                            }

                        }

                    })
                }
                .foregroundColor(.black)
            }
        }
        .listStyle(InsetGroupedListStyle())
        .onAppear {
            viewModel.fetchMyModels()
        }
    }
}

用户界面:

待办事项: 在 AppStorage / UserDefauls 中存储列表“其他一些设置”的检查设置。

【问题讨论】:

  • 在存储到 AppStorage 之前将您的自定义类型编码为字符串或数据(NSUserDefaults 支持的类型)并在加载时解码。
  • This question 向您展示如何订阅和here is 一种编码选项

标签: swift mvvm swiftui userdefaults appstorage


【解决方案1】:

首先我推荐使用 CoreData 而不是 AppStorage

但要回答你的问题:

将此添加到 ViewModel :

// this is a computed variable which changes with subscribedMyModels changes
var encodedSubscribedMyModels : Data? {
    let encoder = JSONEncoder()
    return try? encoder.encode(subscribedMyModels)
}

在你的视野中:

    .onChange(of: viewModel.encodedSubscribedMyModels, perform: { newValue in
        // change @AppStore to newValue
        settings0 =  newValue
    })

注意:您需要使用 JSONDecoder 将数据解码回您的数据模型

【讨论】:

    猜你喜欢
    • 2019-12-06
    • 1970-01-01
    • 1970-01-01
    • 2022-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    相关资源
    最近更新 更多