Xcode报错:Escaping closure captures mutating ‘self’ parameter
Xcode报错:Escaping closure captures mutating ‘self’ parameter

Xcode报错:Escaping closure captures mutating ‘self’ parameter

问题描述

在SwiftUI的入口文件中,我尝试在init()中使用Task调用方法:

@main
struct ImageSlimApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @StateObject var iapManager = IAPManager.shared

    init() {
        KeyboardMonitor.shared.startMonitoring()
        Task {
            await iapManager.loadProduct()  // 加载产品信息
            await iapManager.handleTransactions()  // 加载内购交易更新
        }
    }
    var body: some Scene {
        // 空 Scene,窗口由 AppDelegate 管理
        Settings {}  // 占位,不弹出任何窗口

    }
}

但是Task {} 发生报错:

Task {
    await iapManager.loadProduct()  // 报错,Escaping closure captures mutating 'self' parameter
    await iapManager.handleTransactions()
}

经过查询了解到,在init()中使用Task{}时,因为这个Task闭包捕获了self:

await iapManager.loadProduct()  // iapManager 是 @StateObject var iapManager = IAPManager.shared

self在init()初始化时,是正在构造中的可变结构实体,不能安全地被逃逸闭包捕获。

解决方案

将异步逻辑封装成静态函数或 @MainActor 函数,在 Task 中调用它,避免直接捕获 self:

@main
struct ImageSlimApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @StateObject var iapManager = IAPManager.shared
    
    init() {
        KeyboardMonitor.shared.startMonitoring()
        
        Task {
            await Self.startIAP()   // 在Task中调用 @MainActor函数
        }
    }

    var body: some Scene {
        Settings {} // 空 Scene
    }

    @MainActor  // 封装成 @MainActor 函数
    static func startIAP() async {
        let manager = IAPManager.shared
        await manager.loadProduct()
        await manager.handleTransactions()
    }
}

这样就可以解决报错的问题。

总结

问题的主要原因在于,Swift结构体在init()构造期间,self是可变的。所以不能让self逃逸到异步闭包中。

即使是在Task中访问@StateObject对象,Swift也会任务捕获整个self,从而触发编译器错误。

如果是在mac中使用AppDelegate,也可以将初始化逻辑写进AppDelegate的applicationDidFinishLaunching方法中:

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {
        Task {
            await IAPManager.shared.loadProduct()
            await IAPManager.shared.handleTransactions()
        }
    }
}
   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注