You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SwiftUI类中正确访问AppDelegate?

问题:SwiftUI重构ObservableObject类时无法正确访问AppDelegate

在将遵循ObservableObject协议的类重构为使用@Observable宏标记的过程中,遇到了AppDelegate访问崩溃的问题。

相关代码定义

  1. 自定义AppDelegate:
class AppDelegate: NSObject, UIApplicationDelegate {
    var currentAuthorizationFlow: OIDExternalUserAgentSession?
}
  1. 主App结构体通过@UIApplicationDelegateAdaptor管理AppDelegate:
@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate

    var body: some Scene { ... }
}
  1. 重构前的AuthModel(虽不符合规范但能运行):
class AuthModel: ObservableObject {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    func login() async {
        await withCheckedContinuation { continuation in
            appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
                continuation.resume()
            }
        }
    }
}
  1. 重构后的AuthModel(运行时崩溃):
class AuthModel: ObservableObject {
    func login() async {
        await withCheckedContinuation { continuation in
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
                continuation.resume()
            }
        }
    }
}

崩溃信息

运行时在let appDelegate = UIApplication.shared.delegate as! AppDelegate行崩溃,错误提示:
Could not cast value of type 'SwiftUI.AppDelegate' (0x1ee8bafe8) to 'MyApp.AppDelegate' (0x1052a1c80)

补充场景

AuthModel通过@EnvironmentObject在多个视图中使用,例如登录视图:

struct LoginView: View {
    @EnvironmentObject var authModel: AuthModel

    var body: some View {
        Button {
            Task {
                await authModel.login()
            }
        } label: {
            Text("Log in")
        }
        .buttonStyle(.borderedProminent)
    }
}

解决方案

方法1:依赖注入(推荐)

通过在初始化AuthModel时传入AppDelegate实例,实现解耦且避免类型转换风险,这是最符合SwiftUI设计理念的方式。

  1. 修改AuthModel,添加带参数的初始化方法:
class AuthModel: ObservableObject {
    private let appDelegate: AppDelegate
    
    // 通过初始化注入AppDelegate
    init(appDelegate: AppDelegate) {
        self.appDelegate = appDelegate
    }
    
    func login() async {
        await withCheckedContinuation { continuation in
            appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
                continuation.resume()
            }
        }
    }
}
  1. 在主App结构体中初始化AuthModel并注入AppDelegate,再通过environmentObject传递给视图:
@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
    private let authModel: AuthModel
    
    init() {
        // 注入AppDelegate实例
        authModel = AuthModel(appDelegate: appDelegate)
    }
    
    var body: some Scene {
        WindowGroup {
            LoginView()
                .environmentObject(authModel)
        }
    }
}

方法2:获取SwiftUI包装后的实际AppDelegate

当使用@UIApplicationDelegateAdaptor时,UIApplication.shared.delegate实际是SwiftUI内部的代理对象,你的自定义AppDelegate被它持有在delegate属性中,可以通过以下方式获取:

修改AuthModel中的登录方法:

func login() async {
    await withCheckedContinuation { continuation in
        // 获取SwiftUI的代理包装器,再取出实际的AppDelegate
        let swiftUIDelegate = UIApplication.shared.delegate as! UIApplicationDelegateAdaptor<AppDelegate>
        let appDelegate = swiftUIDelegate.delegate
        
        appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
            continuation.resume()
        }
    }
}

这种方式不需要修改AuthModel的初始化逻辑,但依赖于SwiftUI的内部实现,相比依赖注入灵活性稍差。


内容的提问来源于stack exchange,提问作者Pieter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:20:20