面试题答案
一键面试Task生命周期状态变化
- 待定(Pending):当通过
Task { ... }
创建一个Task时,它最初处于待定状态。此时Task尚未开始执行,等待调度到合适的执行环境。 - 活跃(Active):一旦Task开始执行其闭包中的代码,就进入活跃状态。在这个状态下,Task正在执行它的工作。
- 完成(Finished):当Task闭包中的代码正常执行完毕,没有抛出错误,Task就会进入完成状态。另外,如果Task因为未处理的错误而退出,也会进入完成状态。
优雅取消Task并避免资源泄露
- 使用
CancellationToken
:可以创建一个CancellationToken
并传递给Task。在Task内部,通过检查Task.isCancelled
属性或者在合适的异步操作中传递CancellationToken
来响应取消请求。例如:
let cancellationToken = CancellationToken()
let task = Task {
while !Task.isCancelled {
// 执行任务
try await Task.sleep(nanoseconds: 1_000_000_000)
}
// 清理资源
}
// 取消任务
cancellationToken.cancel()
- 在异步操作中传递
CancellationToken
:许多Swift异步函数支持接收CancellationToken
。比如URLSession
的异步数据加载方法。当传递的CancellationToken
被取消时,相应的异步操作会被取消。
let session = URLSession.shared
let task = Task {
let url = URL(string: "https://example.com")!
do {
let (data, _) = try await session.data(from: url, cancellationToken: cancellationToken)
// 处理数据
} catch {
if let cancellationError = error as? CancellationError, cancellationError.isCancellationRequested {
// 处理取消情况
} else {
// 处理其他错误
}
}
}
- 资源清理:在Task取消时,要确保对已分配的资源进行清理。例如关闭文件句柄、释放网络连接等。在上述例子中,在
while
循环之后可以添加清理资源的代码。如果使用了自定义资源管理类,该类可以实现deinit
方法来确保在对象销毁时清理资源。
通过这些方法,可以优雅地取消Task并有效避免资源泄露问题。