You need to enable JavaScript to run this app. 调用NSUrlSession的reset(completionHandler:)时的任务处理逻辑及等待实现方法
优惠活动
大模型
产品
解决方案
定价
更多

调用NSUrlSession的reset(completionHandler:)时的任务处理逻辑及等待实现方法

reset(completionHandler:)对运行中任务的实际处理逻辑

只要你在URLSession上调用了这个接口,会话里所有还没执行完的任务(不管是正在传输、还是被暂停挂起等待恢复的状态)都会被立刻强制取消,根本不会给任务留跑完的机会。

整个reset的内部执行顺序是固定的:先把所有关联的活跃任务全部终止,再依次清理会话持有的所有本地资源——包括内存/磁盘缓存、存储的认证凭证、Cookie、自定义协议层的缓存数据、下载任务的临时断点文件,等所有内部状态完全清空、没有残留的任务句柄之后,才会触发你传入的completionHandler回调。
不管是普通数据任务、大文件上传任务、下载任务,只要是这个会话持有的,都会被一刀切取消,哪怕任务已经传输到最后1%,也不会自动保留结果或者支持断点恢复。

等待所有现有任务完成后再执行reset的实现方案

想要避免任务被reset强制取消,核心逻辑是在reset执行前做好任务状态追踪,等所有活跃任务自然结束后再触发接口调用,具体落地步骤:

  • 维护原子性的活跃任务计数器。每次给会话提交新任务时,对活跃计数做累加操作;在每个任务的全场景完成回调(成功、失败、主动取消都会触发)里对计数做递减。因为任务回调可能在不同的系统队列触发,所有计数的读写都要通过串行队列或者原子属性做保护,避免多线程竞态导致计数不准。
  • 新增会话待重置状态标记。当外部收到reset触发指令时,先把会话标记为待重置状态,标记生效后立刻停止接收所有新的任务提交,新收到的任务直接取消,不要进入会话队列。
  • 任务完成时的触发判断。在每个任务的完成回调里,计数递减完成后立刻检查两个前提:当前会话是不是处于待重置状态、活跃任务计数是不是已经降到0。两个条件同时满足时,再正式调用reset(completionHandler:)接口。
  • 避坑提醒:不要用getTasksWithCompletionHandler:轮询判断任务是否结束。这种方式不仅会额外占用会话资源,还很容易出现“轮询时查到所有任务都结束了,轮询的间隙又有新任务被提交进来”的竞态,最终导致reset在任务还在运行时被触发。

可以参考下面的简化实现示例:

// 会话状态标记
private var isPendingReset = false
// 任务追踪用的串行队列,保护计数操作
private let taskTrackQueue = DispatchQueue(label: "session.task.tracker")
private var activeTaskCount = 0
private var session: URLSession!

// 提交新任务的方法
func enqueueTask(_ task: URLSessionTask) {
    // 待重置状态下直接拒绝新任务
    guard !isPendingReset else {
        task.cancel()
        return
    }
    
    taskTrackQueue.sync {
        activeTaskCount += 1
    }
    
    // 绑定任务完成回调,做计数递减和状态检查
    task.completionHandler = { [weak self] in
        guard let self = self else { return }
        self.taskTrackQueue.async {
            self.activeTaskCount -= 1
            // 满足待重置+无活跃任务的条件,就触发reset
            if self.activeTaskCount == 0, self.isPendingReset {
                self.session.reset {
                    // 这里写reset完成后的后续逻辑
                }
            }
        }
    }
    task.resume()
}

// 外部调用reset的入口
func requestReset() {
    taskTrackQueue.async {
        self.isPendingReset = true
        // 触发时如果已经没有活跃任务,直接执行reset
        if self.activeTaskCount == 0 {
            self.session.reset {
                // reset完成逻辑
            }
        }
    }
}

补充说明:如果使用的是后台类型的URLSession,需要额外同步系统侧的任务完成事件——因为后台会话的任务哪怕App退到后台,也可能被系统调度继续运行,仅靠前台的任务回调计数会出现漏算,需要结合URLSessionDelegate的相关回调同步计数,保证状态判断准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 11:06:00