取消 Future 中的任务(async/await with combine)

cancel Task inside Future (async/await with combine)

提问人:hessam 提问时间:3/30/2023 最后编辑:hessam 更新时间:3/30/2023 访问量:467

问:

我决定将 async/ await 与 Combine 框架一起使用。 我在 Future 类上使用了一个扩展,并在其中放置了一个 Task 块。 这似乎没问题,我得到了一个结果或错误,但我有一个问题,如果我只想取消我的异步函数的进度,我取消了发布者。

我在扩展程序下面使用了,我在 https://tanaschita.com/20220822-bridge-async-await-to-combine-future/ 上学习

extension Future where Failure == Error {

    convenience init(taskPriority: TaskPriority? = nil, asyncFunc: @escaping () async throws -> Output) {
        self.init { promise in
            Task(priority: taskPriority) {
                do {
                    let result = try await asyncFunc()
                    promise(.success(result))
                } catch {
                    promise(.failure(error))
                }
            }
        }
    }
}

并编写两个帮助函数,用于将数据保存到核心数据中(例如):

func saveIntoCoreData() throws {
        throw DatabaseError.canNotSave
    }

    func doSomeThing() async throws -> String {
        return try await withCheckedThrowingContinuation { continuation in
            do {
                Thread.sleep(forTimeInterval: 5)
                try saveIntoCoreData()
                continuation.resume(with: .success("Result"))
            } catch {
                continuation.resume(with: .failure(error))
            }
        }
    }

最后,我用 Future 调用了这些方法,我预计会得到一个取消错误并停止运行以将数据保存到核心数据中,但刚刚从发布者那里得到一个取消事件,并且数据被保存到核心数据中。

cancelable = Future(taskPriority: .userInitiated) { [weak self] in
            return try await self?.doSomeThing()
        }.eraseToAnyPublisher()
            .sink { completion in
                switch completion {
                case .finished:
                    print("Finished")
                case .failure(let error):
                    print(error.localizedDescription)
                }
            } receiveValue: { value in
                print("result: \(value)")
            }

        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
            self.cancelable?.cancel()
        }

我使用了尝试,但任务没有取消并且没有工作。Task.checkCancellation()

有没有人有停止任务的想法?

Swift 错误处理 async-await future combine

评论

0赞 Scott Thompson 3/30/2023
您的意思是在变量中捕获任务,然后取消任务吗?let my_task = Task{...}my_task.cancel()
0赞 hessam 3/30/2023
@ScottThompson我介绍了如何使用该函数,并且我无法直接访问 Task,因为它是在 Future 扩展中声明的。

答:

1赞 Daniel T. 3/30/2023 #1

期货不能取消,但发布商可以。

使用 Ian Keen 的 AnyPublisher 扩展

然后,您可以:

extension AnyPublisher where Failure == Error {
    init(taskPriority: TaskPriority? = nil, asyncFunc: @escaping () async throws -> Output) {
        self.init { subscriber in
            let task = Task(priority: taskPriority) {
                do {
                    subscriber.send(try await asyncFunc())
                    subscriber.send(completion: .finished)
                } catch {
                    subscriber.send(completion: .failure(error))
                }
            }
            return AnyCancellable { task.cancel() }
        }
    }
}

评论

0赞 hessam 3/30/2023
感谢您的回复,但您的扩展不正确,并且 AnyPublisher 不会使用闭包进行初始化。再次感谢您在 GitHub 上分享扩展和 AnyPublisher,但这个扩展对我的目的没有用,因为我需要将 async await 方法放入其中。也许,我必须改变我的方法,我不知道。
1赞 Daniel T. 3/30/2023
您需要这两个扩展。我上面发布的那个使用了链接中的那个。它完全按照您的要求进行编译和执行操作。再看一遍。
0赞 hessam 3/30/2023
哎呀!我错了,你的回答是正确的。对不起,我犯了一个错误,我没有完整阅读。再次感谢你。