我正在努力将Swift 5.5的并发特性引入我的应用程序,并从一个单一的方法开始。这是我目前掌握的情况:
效用方法
static func fetch<T: GraphQLQuery>(
query: T,
cachePolicy: Apollo.CachePolicy = .default
) async throws -> T.Data? {
try await withCheckedThrowingContinuation { continuation in
Task {
let network = try await Network.shared
network.fetch(
query: query,
cachePolicy: cachePolicy
) { result in
switch result {
case .success:
do {
continuation.resume(with: .success(try result.get().data))
} catch {
continuation.resume(with: .failure(GraphQLResultError.default))
}
case let .failure(error):
continuation.resume(with: .failure(error))
}
}
}
}
}
在调试时,我发现continuation在任意方法上恢复,而不是在调用它们的线程上。从我上面的例子中,network.fetch
的回调总是在主线程上,但是continuation.resume
再次将执行转移到任意线程。
型号编码
static func fetchData() async throws -> [SomeData] {
let query = SomeQuery()
do {
let data = try await Util.fetch(query: query)
// Still on a background thread
return data!
}
}
查看编码
private func fetchData() async {
do {
let data = try await Model.fetchData()
// This feels incorrect since this will be set after the `fetchData` function returns
DispatchQueue.main.async {
result = (Result.success(data), [:])
}
} catch {
result = (Result.failure(error), [:])
}
}
我想应该有一些方法可以在fetch(query:)
方法中运行主线程的延续,这样当我在每个视图上设置属性时就不必切换到主线程。这是MainActor
的用例之一吗?如果我不想使用MainActor
,我该怎么做?
1条答案
按热度按时间kyxcudwk1#
考虑一下你的“视图代码”,在这里你将代码分派到主队列:
在Swift并发中,我们不再使用旧的GCD“分派”模式。相反,如果我们想要在主线程上运行一个属性或方法,我们只需将其隔离到
@MainActor
:或者可以将此方法放在与主参与者隔离的类型中。这将实现同样的事情。
FWIW,许多来自GCD的人被
MainActor.run {…}
吸引,这让人想起我们的老朋友DispatchQueue.main.async {…}
。但是我们真的希望使用全局actor指定,@MainActor
,用于必须在主线程上执行的事情,因为我们现在喜欢对并发代码进行编译时验证。关于将遗留代码转换为
async
-await
的实用技巧,我可能会建议WWDC 2021视频Swift concurrency: Update a sample app。它很好地实际演示了这一迁移过程。