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

SwiftUI:如何从ObservableObject访问AppDelegate数据及最优方案?

How to Pass FCM Token from AppDelegate to AppState in SwiftUI (Without Global Static Properties)

Great question! Relying on global static properties can lead to tight coupling and make your code harder to test, so it's smart to look for better alternatives. Here are a few clean, maintainable approaches to get your FCM token into your AppState class:

1. Inject AppState into AppDelegate (Weak Reference)

This is the most direct approach. We'll pass a weak reference of your AppState to the AppDelegate so it can call methods on it directly when the FCM token is received.

Step 1: Update AppDelegate to hold a weak reference to AppState

import UIKit
import FirebaseMessaging

class AppDelegate: NSObject, UIApplicationDelegate, MessagingDelegate {
    // Use weak to avoid retain cycles
    weak var appState: AppState?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        // Request push notification permissions if needed
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in }
        application.registerForRemoteNotifications()
        return true
    }

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        guard let token = fcmToken else { return }
        // Pass the token directly to AppState
        appState?.updateFCMToken(token)
    }
}

Step 2: Inject AppState into AppDelegate from your SwiftUI App

import SwiftUI

@main
struct ExampleApp: SwiftUI.App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    @StateObject var appState = AppState()

    init() {
        // Pass the AppState reference to the delegate
        delegate.appState = appState
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appState)
        }
    }
}

Step 3: Add the token-handling method to AppState

import Foundation
import Combine

class AppState: ObservableObject {
    @Published var fcmToken: String?

    func updateFCMToken(_ token: String) {
        fcmToken = token
        // Send the token to your server here
        sendTokenToServer(token)
    }

    private func sendTokenToServer(_ token: String) {
        // Implement your API call logic
    }
}

2. Use NotificationCenter for Decoupled Communication

If you prefer a more decoupled approach (so AppDelegate doesn't need a direct reference to AppState), you can use NotificationCenter to broadcast the token when it's received.

Step 1: Define a notification name

extension Notification.Name {
    static let fcmTokenReceived = Notification.Name("FCMTokenReceived")
}

Step 2: Post the notification from AppDelegate

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
    guard let token = fcmToken else { return }
    NotificationCenter.default.post(
        name: .fcmTokenReceived,
        object: nil,
        userInfo: ["token": token]
    )
}

Step 3: Listen for the notification in AppState

class AppState: ObservableObject {
    @Published var fcmToken: String?
    private var cancellables = Set<AnyCancellable>()

    init() {
        // Subscribe to the notification
        NotificationCenter.default.publisher(for: .fcmTokenReceived)
            .compactMap { $0.userInfo?["token"] as? String }
            .sink { [weak self] token in
                self?.fcmToken = token
                self?.sendTokenToServer(token)
            }
            .store(in: &cancellables)
    }

    // ... sendTokenToServer method as before
}

Why Avoid Global Static Properties?

You're right to question this practice:

  • Tight coupling: Static properties create hard dependencies between components, making it harder to modify or test parts of your code in isolation.
  • Memory risks: Static properties live for the entire app lifecycle, which can lead to unintended memory retention if not managed carefully.
  • State inconsistency: If your AppState is ever reinitialized (unlikely with @StateObject, but possible in edge cases), the static property might hold stale data.

Both approaches above avoid these issues while keeping your code clean and maintainable. The first approach is more direct, while the second gives you looser coupling—choose whichever fits your app's architecture best!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:25:23