看下面两个 operation,一个有 throws 一个没有,所以当闭包里面有 try,编译器会直接用有 throws 的初始化方法。
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Task where Failure == Never {
/// Runs the given nonthrowing operation asynchronously
/// as part of a new top-level task on behalf of the current actor.
///
/// Use this function when creating asynchronous work
/// that operates on behalf of the synchronous function that calls it.
/// Like `Task.detached(priority:operation:)`,
/// this function creates a separate, top-level task.
/// Unlike `Task.detached(priority:operation:)`,
/// the task created by `Task.init(priority:operation:)`
/// inherits the priority and actor context of the caller,
/// so the operation is treated more like an asynchronous extension
/// to the synchronous operation.
///
/// You need to keep a reference to the task
/// if you want to cancel it by calling the `Task.cancel()` method.
/// Discarding your reference to a detached task
/// doesn't implicitly cancel that task,
/// it only makes it impossible for you to explicitly cancel the task.
///
/// - Parameters:
/// - priority: The priority of the task.
/// Pass `nil` to use the priority from `Task.currentPriority`.
/// - operation: The operation to perform.
@discardableResult
public init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success)
}
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Task where Failure == Error {
/// Runs the given throwing operation asynchronously
/// as part of a new top-level task on behalf of the current actor.
///
/// Use this function when creating asynchronous work
/// that operates on behalf of the synchronous function that calls it.
/// Like `Task.detached(priority:operation:)`,
/// this function creates a separate, top-level task.
/// Unlike `detach(priority:operation:)`,
/// the task created by `Task.init(priority:operation:)`
/// inherits the priority and actor context of the caller,
/// so the operation is treated more like an asynchronous extension
/// to the synchronous operation.
///
/// You need to keep a reference to the task
/// if you want to cancel it by calling the `Task.cancel()` method.
/// Discarding your reference to a detached task
/// doesn't implicitly cancel that task,
/// it only makes it impossible for you to explicitly cancel the task.
///
/// - Parameters:
/// - priority: The priority of the task.
/// Pass `nil` to use the priority from `Task.currentPriority`.
/// - operation: The operation to perform.
@discardableResult
public init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success)
}
在哪里获取 throws 出来的 error ?
看下面两个实现,有 throws 的 Task result 的类型 Result<Success, Failure>,另一个是 Never,所以就是两种实现。
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Task where Failure == Never {
/// The result from a nonthrowing task, after it completes.
///
/// If the task hasn't completed yet,
/// accessing this property waits for it to complete
/// and its priority increases to that of the current task.
/// Note that this might not be as effective as
/// creating the task with the correct priority,
/// depending on the executor's scheduling details.
///
/// Tasks that never throw an error can still check for cancellation,
/// but they need to use an approach like returning `nil`
/// instead of throwing an error.
public var value: Success { get async }
}
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Task {
/// The result from a throwing task, after it completes.
///
/// If the task hasn't completed,
/// accessing this property waits for it to complete
/// and its priority increases to that of the current task.
/// Note that this might not be as effective as
/// creating the task with the correct priority,
/// depending on the executor's scheduling details.
///
/// If the task throws an error, this property propagates that error.
/// Tasks that respond to cancellation by throwing `CancellationError`
/// have that error propagated here upon cancellation.
///
/// - Returns: The task's result.
public var value: Success { get async throws }
/// The result or error from a throwing task, after it completes.
///
/// If the task hasn't completed,
/// accessing this property waits for it to complete
/// and its priority increases to that of the current task.
/// Note that this might not be as effective as
/// creating the task with the correct priority,
/// depending on the executor's scheduling details.
///
/// - Returns: If the task succeeded,
/// `.success` with the task's result as the associated value;
/// otherwise, `.failure` with the error as the associated value.
public var result: Result<Success, Failure> { get async }
/// Indicates that the task should stop running.
///
/// Task cancellation is cooperative:
/// a task that supports cancellation
/// checks whether it has been canceled at various points during its work.
///
/// Calling this method on a task that doesn't support cancellation
/// has no effect.
/// Likewise, if the task has already run
/// past the last point where it would stop early,
/// calling this method has no effect.
///
/// - SeeAlso: `Task.checkCancellation()`
public func cancel()
}
看看下面 task1 和 task2 的区别
Task {
// task 1
let task = Task {
let a: Int = try await withCheckedThrowingContinuation { contination in
contination.resume(with: .failure("1234"))
}
}
do {
let value = try await task.value
} catch {
}
// task 2
Task {
do {
let a: Int = try await withCheckedThrowingContinuation { contination in
contination.resume(with: .failure("1234"))
}
} catch {
}
}
}
总结:Task 没有 throws 的,Result 的 Failure 是 Never,编译器根据你闭包中的代码,直接生成,完全是两种实现。
抽象的确实够狠。
https://forums.swift.org/t/correct-way-of-dealing-with-throwing-functions-inside-a-task/59705
https://forums.swift.org/t/task-initializer-with-throwing-closure-swallows-error/56066