如何使用 swift combine 异步处理任务数组
How to process an array of task asynchronously with swift combine
我有一个发布者接受网络调用和 returns ID 数组。我现在需要为每个 ID 调用另一个网络调用以获取我的所有数据。我希望最终发布者拥有结果对象。
第一个网络结果:
"user": {
"id": 0,
"items": [1, 2, 3, 4, 5]
}
最终对象:
struct User {
let id: Int
let items: [Item]
... other fields ...
}
struct Item {
let id: Int
... other fields ...
}
处理多个网络调用:
userPublisher.flatMap { user in
let itemIDs = user.items
return Future<[Item], Never>() { fulfill in
... OperationQueue of network requests ...
}
}
我想并行执行网络请求,因为它们彼此不依赖。我不确定 Future 是否就在这里,但我想我会有代码来做一个
DispatchGroup 或 OperationQueue 并在它们全部完成后执行。是否有更多的 Combine 方法可以做到这一点?
Doe Combine 是否有将一个流拆分为多个并行流并将这些流连接在一起的概念?
Combine 提供围绕 URLSession
的扩展来处理网络请求,除非您确实需要与基于 OperationQueue
的网络集成,那么 Future
是一个不错的选择。您可以 运行 多个 Future
并在某个时候收集它们,但我真的建议您查看 Combine 的 URLSession
扩展。
struct User: Codable {
var username: String
}
let requestURL = URL(string: "https://example.com/")!
let publisher = URLSession.shared.dataTaskPublisher(for: requestURL)
.map { [=10=].data }
.decode(type: User.self, decoder: JSONDecoder())
关于运行批量请求,可以使用Publishers.MergeMany
,即:
struct User: Codable {
var username: String
}
let userIds = [1, 2, 3]
let subscriber = Just(userIds)
.setFailureType(to: Error.self)
.flatMap { (values) -> Publishers.MergeMany<AnyPublisher<User, Error>> in
let tasks = values.map { (userId) -> AnyPublisher<User, Error> in
let requestURL = URL(string: "https://jsonplaceholder.typicode.com/users/\(userId)")!
return URLSession.shared.dataTaskPublisher(for: requestURL)
.map { [=11=].data }
.decode(type: User.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
return Publishers.MergeMany(tasks)
}.collect().sink(receiveCompletion: { (completion) in
if case .failure(let error) = completion {
print("Got error: \(error.localizedDescription)")
}
}) { (allUsers) in
print("Got users:")
allUsers.map { print("\([=11=])") }
}
在上面的示例中,我使用 collect
来收集所有结果,这会推迟向 Sink
发送值,直到所有网络请求都成功完成,但是您可以去掉 collect
并在网络请求完成时一一接收上面示例中的每个 User
。
我有一个发布者接受网络调用和 returns ID 数组。我现在需要为每个 ID 调用另一个网络调用以获取我的所有数据。我希望最终发布者拥有结果对象。
第一个网络结果:
"user": {
"id": 0,
"items": [1, 2, 3, 4, 5]
}
最终对象:
struct User {
let id: Int
let items: [Item]
... other fields ...
}
struct Item {
let id: Int
... other fields ...
}
处理多个网络调用:
userPublisher.flatMap { user in
let itemIDs = user.items
return Future<[Item], Never>() { fulfill in
... OperationQueue of network requests ...
}
}
我想并行执行网络请求,因为它们彼此不依赖。我不确定 Future 是否就在这里,但我想我会有代码来做一个 DispatchGroup 或 OperationQueue 并在它们全部完成后执行。是否有更多的 Combine 方法可以做到这一点?
Doe Combine 是否有将一个流拆分为多个并行流并将这些流连接在一起的概念?
Combine 提供围绕 URLSession
的扩展来处理网络请求,除非您确实需要与基于 OperationQueue
的网络集成,那么 Future
是一个不错的选择。您可以 运行 多个 Future
并在某个时候收集它们,但我真的建议您查看 Combine 的 URLSession
扩展。
struct User: Codable {
var username: String
}
let requestURL = URL(string: "https://example.com/")!
let publisher = URLSession.shared.dataTaskPublisher(for: requestURL)
.map { [=10=].data }
.decode(type: User.self, decoder: JSONDecoder())
关于运行批量请求,可以使用Publishers.MergeMany
,即:
struct User: Codable {
var username: String
}
let userIds = [1, 2, 3]
let subscriber = Just(userIds)
.setFailureType(to: Error.self)
.flatMap { (values) -> Publishers.MergeMany<AnyPublisher<User, Error>> in
let tasks = values.map { (userId) -> AnyPublisher<User, Error> in
let requestURL = URL(string: "https://jsonplaceholder.typicode.com/users/\(userId)")!
return URLSession.shared.dataTaskPublisher(for: requestURL)
.map { [=11=].data }
.decode(type: User.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
return Publishers.MergeMany(tasks)
}.collect().sink(receiveCompletion: { (completion) in
if case .failure(let error) = completion {
print("Got error: \(error.localizedDescription)")
}
}) { (allUsers) in
print("Got users:")
allUsers.map { print("\([=11=])") }
}
在上面的示例中,我使用 collect
来收集所有结果,这会推迟向 Sink
发送值,直到所有网络请求都成功完成,但是您可以去掉 collect
并在网络请求完成时一一接收上面示例中的每个 User
。