如何让@AppStorage 在 MVVM / SwiftUI 框架中工作?

Posted

技术标签:

【中文标题】如何让@AppStorage 在 MVVM / SwiftUI 框架中工作?【英文标题】:How can I get @AppStorage to work in an MVVM / SwiftUI framework? 【发布时间】:2021-04-21 20:48:35 【问题描述】:

我的整个应用程序都有一个 SettingsManager 单例,其中包含大量用户设置。而且我有几个ViewModels 可以参考并且可以编辑SettingsManager

应用程序基本上是这样的......

import PlaygroundSupport
import Combine
import SwiftUI

class SettingsManager: ObservableObject 
    static let shared = SettingsManager()

    @AppStorage("COUNT") var count = 10


class ViewModel: ObservableObject 
    @Published var settings = SettingsManager.shared
    
    func plus1() 
        settings.count += 1
        objectWillChange.send()
    


struct ContentView: View 
    @StateObject var viewModel = ViewModel()
    var body: some View 
        VStack 
            Button(action: viewModel.plus1) 
                Text("\(viewModel.settings.count)")
            
        
    


let viewController = UIHostingController(rootView: ContentView())

PlaygroundPage.current.liveView = viewController

令人沮丧的是,它在大约 85% 的时间里都有效。但 15% 的情况下,值不会更新,直到导航离开视图然后返回。

如何让@AppStorage 与我的视图模型/MVVM 框架配合使用?!

【问题讨论】:

当你有一个发布共享对象的视图模型时,这是一个奇怪的设计。对我来说,如果 SettingsManager 进行发布会更有意义 同意!这就是为什么我试图通过尝试@AppStorage("COUNT") var count = 10 willSet objectWillChange.send() 来回答我的问题,但这不是灵丹妙药:( 是的,我实际上只是看到了那个代码,那么你的回答对我来说更有意义 关于如何调整该代码以使其 100% 一致的任何想法? @AppStorage 并不是真正用于对象 - 它是用于视图内部的,例如 @State@StateObject 【参考方案1】:

此 SettingsManager 在可取消集解决方案中改编自开源ACHN App:

import PlaygroundSupport
import Combine
import SwiftUI

class SettingsManager: ObservableObject 
    static let shared = SettingsManager()

    @AppStorage("COUNT") var count = 10 
        willSet  objectWillChange.send() 
    


class ViewModel: ObservableObject 
    @Published var settings = SettingsManager.shared
    var cancellables = Set<AnyCancellable>()
    
    init() 
        settings.objectWillChange
            .sink  [weak self] _ in
                self?.objectWillChange.send()
            
            .store(in: &cancellables)
    
    
    func plus1() 
        settings.count += 1
    


struct ContentView: View 
    @StateObject var viewModel = ViewModel()
    var body: some View 
        VStack 
            Button(action: viewModel.plus1) 
                Text(" \(viewModel.settings.count) ")
            
        
    


let viewController = UIHostingController(rootView: ContentView())

PlaygroundPage.current.liveView = viewController

似乎没有那么小故障,但仍然不是 100% 坚如磐石的一致:(

把这个留在这里,希望能用我的尝试激励别人

【讨论】:

以上是关于如何让@AppStorage 在 MVVM / SwiftUI 框架中工作?的主要内容,如果未能解决你的问题,请参考以下文章

使用 @AppStorage 进行设置的 SwiftUI 最佳实践:如何在加载 @AppStorage 之前读取 UserDefaults?

如何在 ViewModel 中使用带有自定义类型和 @Published 的 @AppStorage?

SwiftUI:绑定到@AppStorage

更新单独结构中的@AppStorage 后如何更新 SwiftUI 视图

使用@AppStorage 保存唯一的字符串数组

AppStorage 与 CoreData