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

如何避免async函数持有self引用且无需显式取消Task?

问题解决:异步方法执行时避免强引用self的两种简洁方案

你的代码中,fetchMovies作为实例异步方法,执行期间会强引用self,导致TestViewModel实例无法在任务完成前被销毁(deinit不会立即触发)。结合你不想显式管理Task、不想合并代码的需求,以下是两个直接的解决办法:


方案一:静态方法+弱引用参数

将fetchMovies改为静态方法,传入weak self作为参数。静态方法不会强持有self,仅在需要访问实例成员时检查弱引用有效性,任务执行期间不会阻碍实例销毁:

class TestViewModel {
    init() {
        print("Init")
        Task { [weak self] in
            await Self.fetchMovies(for: self)
        }
    }
    
    deinit {
        print("Deinit")
    }
    
    static func fetchMovies(for weakSelf: TestViewModel?) async {
        try? await Task.sleep(nanoseconds: 3 * 1_000_000_000)
        
        // 仅当self仍存在时,执行依赖实例的后续操作
        guard let self = weakSelf else { return }
        print("后续实例操作:\(self)")
    }
}

这个方案逻辑拆分清晰,无需管理Task,也不会强持self。当TestViewModel实例被释放时,weakSelf会变为nil,后续依赖实例的代码自动跳过,实例可以正常执行deinit。


方案二:隐式绑定Task到实例,deinit自动取消

通过关联对象将Task隐式绑定到self,在deinit时自动取消任务。无需显式声明Task属性,任务会随实例销毁而终止,打破self的强引用:

import ObjectiveC

private var AssociatedTaskKey: UInt8 = 0

class TestViewModel {
    init() {
        print("Init")
        let task = Task { [weak self] in
            await self?.fetchMovies()
        }
        // 用关联对象隐式存储Task
        objc_setAssociatedObject(self, &AssociatedTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    
    deinit {
        print("Deinit")
        // 实例销毁时自动取消Task
        if let task = objc_getAssociatedObject(self, &AssociatedTaskKey) as? Task<Void> {
            task.cancel()
        }
    }
    
    func fetchMovies() async {
        do {
            try await Task.sleep(nanoseconds: 3 * 1_000_000_000)
            print("任务完成")
        } catch is CancellationError {
            print("任务随实例销毁被取消")
        } catch {
            // 处理其他错误
        }
    }
}

这个方案保留了fetchMovies的实例方法结构,Task的管理完全隐式。当实例销毁时,Task被自动取消,Task.sleep会抛出CancellationError,任务提前终止,self的强引用被释放。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:07:52