Tiercel 3.3.0
Tiercel 3.3.0 重点改进了下载任务的状态管理、App 重启恢复、并发调度和 resumeData 处理。本版本修复了多个任务可能卡在中间状态、无法重新开始或遗留旧底层传输的问题。
主要改进
更清晰的任务状态语义
willSuspend、willCancel和willRemove已废弃,Tiercel 不再对外触发这些中间状态。suspend在内部记录异步暂停意图,并等待URLSession回调产生resumeData后再收敛为.suspended。- 暂停请求发出后会立即释放 Tiercel 的并发槽位,不阻塞后续等待任务的调度。
cancel和remove立即完成逻辑状态转换,后到的系统回调仅负责底层资源和映射清理。- 重复调用
suspend不再覆盖第一次操作的 handler,也不会重复释放并发槽位。 - 重复启动已成功任务时,不再重放 Task 或 Manager 的 success/completion 回调,也不会让 Manager 在
.succeeded和.running之间假转换。
App 重启和后台任务恢复
- 新增缓存任务与
URLSession.getAllTasks()的对账逻辑。 - 恢复时按逻辑任务对系统 transfer 分组,并为每个任务选择唯一的权威 transfer。
- 当同一逻辑任务存在多个底层 transfer 时,优先保留运行中、进度更多或更新的 transfer,并清理其余重复传输。
- 过期 transfer 的延迟回调不再覆盖当前任务的进度、
resumeData或最终状态。 - 缓存为
.running但系统中已没有对应 transfer 的孤儿任务,会收敛为.suspended,允许用户安全地重新开始。 - 会话重建期间的 start 请求现在会保留完整的 task、handler 和回调队列配置,待新 session 可用后再正式启动。
- 恢复和重建期间不再伪造“暂停 → 重启”流程,也不会提前触发 control/failure/completion 回调。
- 纠正了重定向或
currentRequest == nil时的任务映射,避免丢失进度、文件完成或最终完成回调。
更可靠的断点续传
- 重新整理
resumeData的解析、修复、编码和持久化流程。 - 兼容旧版 resumeData v1 通过
NSURLSessionResumeInfoLocalPath保存临时文件路径的格式。 - 支持新版 resumeData 中的
NSURLSessionResumeInfoTempFileName。 - 损坏或无法解析的
resumeData不再引发强制解包崩溃。 - 替换
resumeData时会清理已失效的旧临时文件,避免长期遗留缓存。 - 如果暂停过程中文件已经完整下载,会保留用户请求的
.suspended状态;下次启动时可直接根据本地文件收敛为成功。 - 暂停恢复回调会保留有效的 HTTP response,不再因恢复流程丢失响应信息。
并发、缓存和线程安全
- 集中管理 Manager 和 Task 的可变状态,降低跨队列读写竞争。
- 修复
tasksSort在 operation queue 内部重入时可能发生的死锁。 - 避免持有状态锁时调用
URLSessionTask.suspend()或resume()。 - 缓存的文件检查、写入和删除统一通过 I/O queue 串行化。
- 单条持久化任务损坏时,现在只跳过该条目,不再将整份任务缓存静默清空。
- Manager 会拒绝操作属于其他 Manager 的 Task,避免误操作同 URL 任务或触发队列断言。
- 单任务
cancel/remove删除最后一个任务时,Manager 现在会正确执行 completion;批量操作不会重复触发 Manager completion。 - Manager 进入
.suspended后会正确停止计时器和网络活动指示器。
回调和进度语义
- 在任务已经进入终态后注册 success/failure/completion handler,会根据当前状态补发对应回调。
- 最终 100% progress 回调触发时,Task 状态已经是
.succeeded。 - 完成文件在无法建立正确的底层任务映射时不再被静默忽略后错误地标记成功。
- 统一 Manager 恢复过程中 completed/suspended 状态的收尾逻辑,确保状态持久化、计时器清理和 completion 语义一致。
兼容性与升级说明
任务恢复语义
- 应用重启后,持久化的
.waiting任务仍会恢复为.suspended,与旧版本保持一致。 - 需要调用
start或totalStart才会重新启动这些任务。 - 历史缓存中的
.willSuspend、.willCancel和.willRemove会分别收敛为.suspended、.canceled和.removed。
有限的源码兼容性变化
3.3.0 保留了主要下载 API,但包含以下源码级变化:
Logable现在继承AnyObject,需要由引用类型实现。Logger由struct改为class。LogType关联值的顺序和标签已调整。SessionManager.logger由可写改为只读;如需自定义 Logger,请在初始化 Manager 时传入。SessionManager.invalidate()不再是公开 API,Session 生命周期现在由 Manager 内部管理。Task.manager公开只读属性已移除;Task 与 Manager 的关联现在由 Tiercel 内部管理,不应再通过task.manager反查 Manager。Cache.invalidate()公开方法已移除;Cache 的解码上下文和生命周期现在由 Tiercel 内部管理。Protected不再是@propertyWrapper,同时移除了wrappedValue、projectedValue和init(wrappedValue:)。如果下游代码直接使用@Protected,需要改为显式创建Protected(value)并通过read/write访问。- 新增只读属性
SessionManager.canRunImmediately。 Status.willSuspend、Status.willCancel和Status.willRemove仍保留以缓解编译迁移,但已标记为 deprecated,且运行时不再触发。
测试
本版本包含针对以下场景的回归测试:
- 重复暂停与并发槽位释放
- 单任务与批量 cancel/remove
- 延迟回调和过期 transfer 清理
- 底层 transfer 选择与恢复对账
- 无
currentRequest时的完成文件映射 - 损坏缓存任务和损坏
resumeData - resumeData v1/v2 临时文件名兼容
- 重启已成功任务的幂等语义
- 持久化
.waiting恢复为.suspended - 最终 progress 回调的状态顺序
当前回归测试共 29 个,全部通过。
致谢
感谢 Issue #222 的反馈和复现信息,以及所有帮助验证暂停、取消、删除与后台恢复流程的使用者。