从同步和异步闭包中捕获值
Capturing values from synchronous and asynchronous closures
假设一个像这样的简单结构:
struct Foo {
let value: Int
let delay: TimeInterval
}
它有2个函数,每个函数都以一个闭包作为参数。一个是同步调用的,另一个是在delay
:
之后异步调用的
extension Foo {
func sync(_ completion: (Int) -> Void) {
completion(value)
}
}
extension Foo {
func async(_ completion: @escaping (Int) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(delay)) {
completion(self.value)
}
}
}
现在假设我有一个 Foo
对象数组:
let foo1 = Foo(value: 1, delay: 1)
let foo2 = Foo(value: 2, delay: 0)
现在我想查询它们中的每一个以获取它们将提供的值并将它们放入一个数组中。同步的话,可以这样做:
let syncValues = [foo1, foo2].reduce(into: []) { values, foo in foo.sync { values.append([=13=]) } } // [1, 2]
异步,我想这样做并在 foo1
之前让 foo2
报告:
let asyncValues = [foo1, foo2].reduce(into: []) { values, foo in foo.async { values.append([=14=]) } // [2, 1]}
但是,当我尝试执行异步版本时出现错误:
Escaping closure captures 'inout' parameter 'values'
执行此异步任务的好方法是什么?
因为它是异步的,所以不能在单个同步语句中执行此操作。假设您理解这一点,使用 Combine 可能是最简单的:
import Combine
let fooResultsPublishers = [foo1, foo2].publisher
.flatMap { foo in
Future { promise in
foo.async { promise(.success([=10=])) }
}
}
.collect()
要真正获取值,您需要使用.sink
对其进行异步操作:
fooResultsPublishers
.sink {
print([=11=]) // [2,1]
}
// store it in long-living property, like
// var cancellables: Set<AnyCancellable> = []
.store(in: &cancellables)
如果没有 Combine,您需要使用类似 DispatchGroup
:
的东西
let group = DispatchGroup()
var values: [Int] = []
[foo1, foo2].forEach { foo in
group.enter()
foo.async { values.append([=12=]); group.leave() }
}
group.notify(queue: .main) {
print(values) // [2,1]
}
假设一个像这样的简单结构:
struct Foo {
let value: Int
let delay: TimeInterval
}
它有2个函数,每个函数都以一个闭包作为参数。一个是同步调用的,另一个是在delay
:
extension Foo {
func sync(_ completion: (Int) -> Void) {
completion(value)
}
}
extension Foo {
func async(_ completion: @escaping (Int) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(delay)) {
completion(self.value)
}
}
}
现在假设我有一个 Foo
对象数组:
let foo1 = Foo(value: 1, delay: 1)
let foo2 = Foo(value: 2, delay: 0)
现在我想查询它们中的每一个以获取它们将提供的值并将它们放入一个数组中。同步的话,可以这样做:
let syncValues = [foo1, foo2].reduce(into: []) { values, foo in foo.sync { values.append([=13=]) } } // [1, 2]
异步,我想这样做并在 foo1
之前让 foo2
报告:
let asyncValues = [foo1, foo2].reduce(into: []) { values, foo in foo.async { values.append([=14=]) } // [2, 1]}
但是,当我尝试执行异步版本时出现错误:
Escaping closure captures 'inout' parameter 'values'
执行此异步任务的好方法是什么?
因为它是异步的,所以不能在单个同步语句中执行此操作。假设您理解这一点,使用 Combine 可能是最简单的:
import Combine
let fooResultsPublishers = [foo1, foo2].publisher
.flatMap { foo in
Future { promise in
foo.async { promise(.success([=10=])) }
}
}
.collect()
要真正获取值,您需要使用.sink
对其进行异步操作:
fooResultsPublishers
.sink {
print([=11=]) // [2,1]
}
// store it in long-living property, like
// var cancellables: Set<AnyCancellable> = []
.store(in: &cancellables)
如果没有 Combine,您需要使用类似 DispatchGroup
:
let group = DispatchGroup()
var values: [Int] = []
[foo1, foo2].forEach { foo in
group.enter()
foo.async { values.append([=12=]); group.leave() }
}
group.notify(queue: .main) {
print(values) // [2,1]
}