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

如何在非异步方法中实现异步任务串行执行,解决多远程通知触发时同步任务顺序混乱问题

如何在非异步方法中实现异步任务串行执行,解决多远程通知触发时同步任务顺序混乱问题

我太懂你现在的困扰了——多个远程通知触发后,原本期望串行执行的异步任务全挤在一起跑,日志顺序乱得一塌糊涂,完全不是你想要的逐个完整执行的效果。

咱们先搞清楚问题出在哪:你在同步的application(_:didReceiveRemoteNotification:)方法里,每次都新建一个Task去调用fetchAllChangesAsync,而这些Task默认会在全局并发队列上执行,相当于多个任务同时开工,自然就会出现start fetching、start saving穿插的情况。

要解决这个问题,核心就是把这些异步任务强制排成串行队列,一个执行完再启动下一个,这里有两个实用方案,推荐优先用更贴合Swift现代并发风格的那个:

方案一:用Actor实现串行执行(推荐)

Actor是Swift 5.5+引入的并发原语,它的核心特性就是所有方法都是串行执行的——不管有多少个异步调用请求,都会排队等待上一个任务完成后再执行。

你只需要把CloudAssistant的类声明改成actor就行,其他逻辑几乎不用动:

@MainActor
actor CloudAssistant: ObservableObject {
    static let shared = CloudAssistant()
    
    func fetchAllChangesAsync() async throws {
        defer {
            // 保留你原来的defer逻辑
        }
        print("start fetching")
        // 这里的CloudKit异步请求代码不变
        // 这里的Core Data更新await代码不变
        print("start saving")
        print("end saving")
    }
}

然后在ApplicationDelegate里的调用代码不用改,还是原来的样子:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    print("✅fetching changes")
    Task {
        try await CloudAssistant.shared.fetchAllChangesAsync()
    }
}

这样修改后,即使多个通知触发,每个fetchAllChangesAsync调用都会在Actor的串行执行队列里排队,严格按照「start fetching → start saving → end saving」的完整流程逐个执行,完全符合你想要的日志顺序。

方案二:自定义串行任务队列(兼容旧版本Swift)

如果你的项目还没升级到支持Actor的Swift版本,也可以用DispatchQueue创建一个自定义的串行队列,把异步任务包装在队列里执行:

@MainActor
class CloudAssistant: ObservableObject {
    static let shared = CloudAssistant()
    // 创建一个专属串行队列
    private let serialQueue = DispatchQueue(label: "com.yourname.cloudassistant.serial")
    
    func fetchAllChangesAsync() async throws {
        // 用withCheckedThrowingContinuation把串行队列的操作桥接到async/await
        try await withCheckedThrowingContinuation { continuation in
            serialQueue.async { [weak self] in
                guard let self = self else {
                    continuation.resume(throwing: NSError(domain: "CloudAssistant", code: -1, userInfo: [NSLocalizedDescriptionKey: "实例已释放"]))
                    return
                }
                
                Task {
                    do {
                        defer {
                            // 保留原来的defer逻辑
                        }
                        print("start fetching")
                        // 这里的CloudKit异步请求
                        // 这里的Core Data更新await方法
                        print("start saving")
                        print("end saving")
                        
                        continuation.resume()
                    } catch {
                        continuation.resume(throwing: error)
                    }
                }
            }
        }
    }
}

不过这种方法需要手动处理async/await和DispatchQueue的桥接,代码相对繁琐,还是更推荐用Actor的方案,更符合Swift现代并发的设计思路。

不管用哪种方案,最终都能实现你想要的执行顺序:

✅fetching changes
✅fetching changes
✅fetching changes
start fetching
start saving
end saving
start fetching
start saving
end saving
start fetching
start saving
end saving

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 12:19:35