macOS SwiftUI中ViewModel先于AppDelegate执行的解决办法咨询
macOS SwiftUI中ViewModel先于AppDelegate执行的问题解决方案
执行顺序是否正常?
这种断点触发顺序(2→3→1)是正常现象。原因在于:
@NSApplicationDelegateAdaptor只是将AppDelegate接入SwiftUI的App生命周期,但AppDelegate的applicationDidFinishLaunching是在应用完成整个启动流程后才触发的系统回调。- SwiftUI的
@StateObject会在App结构体初始化阶段就创建实例,这个时机早于applicationDidFinishLaunching的执行,因此会出现ViewModel先初始化、后执行UserDefaults注册的情况。
解决方案
方案1:延迟ViewModel初始化(适配遗留AppDelegate场景)
给AppDelegate添加启动完成的标志位,在applicationDidFinishLaunching中标记完成,再在SwiftUI App的生命周期回调中触发ViewModel的初始化:
// 修改AppDelegate.swift final class AppDelegate: NSObject, NSApplicationDelegate { @Published var isLaunchFinished = false func applicationDidFinishLaunching(_ notification: Notification) { UserDefaults.shared.register(defaults: [ "userDefaultItem1" : false, "userDefaultItem2" : 0 ]) isLaunchFinished = true } } // 修改AppName.swift @main struct AppName: App { @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate @StateObject private var vm: ViewModel? = nil var body: some Scene { WindowGroup { if let vm = vm { ContentView() .environmentObject(vm) } else { ProgressView("启动中...") } } .onChange(of: appDelegate.isLaunchFinished) { finished in if finished { _vm = StateObject(wrappedValue: ViewModel()) } } } }
方案2:在ViewModel中补注册UserDefaults
由于UserDefaults.register(defaults:)只是设置默认值,不会覆盖已保存的用户数据,因此可以在ViewModel初始化时重复执行注册逻辑,避免依赖AppDelegate的时机:
class ViewModel: ObservableObject { init() { // 与AppDelegate中一致的默认值注册 UserDefaults.shared.register(defaults: [ "userDefaultItem1" : false, "userDefaultItem2" : 0 ]) // 后续访问UserDefaults即可正常获取默认值 let item1 = UserDefaults.shared.bool(forKey: "userDefaultItem1") } }
方案3:改用SwiftUI原生生命周期回调(macOS 12+)
如果可以部分替代AppDelegate的启动逻辑,使用SwiftUI的onLaunch回调(需macOS 12及以上)在ViewModel初始化前完成UserDefaults注册:
@main struct AppName: App { @StateObject private var vm: ViewModel? = nil var body: some Scene { WindowGroup { if let vm = vm { ContentView() .environmentObject(vm) } else { ProgressView("启动中...") } } .onLaunch { UserDefaults.shared.register(defaults: [ "userDefaultItem1" : false, "userDefaultItem2" : 0 ]) _vm = StateObject(wrappedValue: ViewModel()) } } }
内容的提问来源于stack exchange,提问作者markb
相关产品推荐
相关产品推荐

