Combine combineLatest 不等待上一个操作触发
Combine combineLatest is not waiting for the previous operation to fire
如果您在 Playgroud 中尝试此代码:
import Combine
import Foundation
struct User {
let name: String
}
private var subscriptions = Set<AnyCancellable>()
var didAlreadyImportUsers = false
var users = [User]()
func importUsers() -> Future<Bool, Never> {
Future { promise in
DispatchQueue.global(qos: .userInitiated).async {
sleep(5)
users = [User(name: "John"), User(name: "Jack")]
promise(.success(true))
}
}
}
func getUsers(age: Int? = nil) ->Future<[User], Error> {
Future { promise in
promise(.success(users))
}
}
var usersPublisher: AnyPublisher<[User], Error> {
if didAlreadyImportUsers {
return getUsers().eraseToAnyPublisher()
} else {
return importUsers()
.setFailureType(to: Error.self)
.combineLatest(getUsers())
.map { [=10=].1 }
.eraseToAnyPublisher()
}
}
usersPublisher
.sink(receiveCompletion: { completion in
print(completion)
}, receiveValue: { value in
print(value)
}).store(in: &subscriptions)
它将打印:
[]
finished
但我预计:
[User(name: "John"), User(name: "Jack")]
finished
如果我删除带有 sleep(5)
的行,那么它会正确打印结果。这似乎是异步性的问题。好像 .combineLatest(getUsers())
没有在等待 importUsers()
我认为 combineLatest
正在处理这个问题?我在这里缺少什么?
(在我的真实代码中有一个很长的 运行 核心数据操作而不是 sleep
)
CombineLatest
会等待,正如您正确预期的那样,但在您的情况下 getUsers
已经准备好一个值,即 []
;即 users
是什么时候 getUsers
运行.
在某些异步操作发生之前,您实际上不需要使用 CombineLatest
到 "wait"。您可以只链接发布者:
return importUsers()
.setFailureType(to: Error.self)
.flatMap { _ in
getUsers()
}
.eraseToAnyPublisher()
事实上,甚至不需要 getUsers
,如果您可以假设 users
在 importUsers
之后填充:
return importUsers()
.map { _ in
self.users
}
.eraseToAnyPublisher()
如果您在 Playgroud 中尝试此代码:
import Combine
import Foundation
struct User {
let name: String
}
private var subscriptions = Set<AnyCancellable>()
var didAlreadyImportUsers = false
var users = [User]()
func importUsers() -> Future<Bool, Never> {
Future { promise in
DispatchQueue.global(qos: .userInitiated).async {
sleep(5)
users = [User(name: "John"), User(name: "Jack")]
promise(.success(true))
}
}
}
func getUsers(age: Int? = nil) ->Future<[User], Error> {
Future { promise in
promise(.success(users))
}
}
var usersPublisher: AnyPublisher<[User], Error> {
if didAlreadyImportUsers {
return getUsers().eraseToAnyPublisher()
} else {
return importUsers()
.setFailureType(to: Error.self)
.combineLatest(getUsers())
.map { [=10=].1 }
.eraseToAnyPublisher()
}
}
usersPublisher
.sink(receiveCompletion: { completion in
print(completion)
}, receiveValue: { value in
print(value)
}).store(in: &subscriptions)
它将打印:
[]
finished
但我预计:
[User(name: "John"), User(name: "Jack")]
finished
如果我删除带有 sleep(5)
的行,那么它会正确打印结果。这似乎是异步性的问题。好像 .combineLatest(getUsers())
没有在等待 importUsers()
我认为 combineLatest
正在处理这个问题?我在这里缺少什么?
(在我的真实代码中有一个很长的 运行 核心数据操作而不是 sleep
)
CombineLatest
会等待,正如您正确预期的那样,但在您的情况下 getUsers
已经准备好一个值,即 []
;即 users
是什么时候 getUsers
运行.
在某些异步操作发生之前,您实际上不需要使用 CombineLatest
到 "wait"。您可以只链接发布者:
return importUsers()
.setFailureType(to: Error.self)
.flatMap { _ in
getUsers()
}
.eraseToAnyPublisher()
事实上,甚至不需要 getUsers
,如果您可以假设 users
在 importUsers
之后填充:
return importUsers()
.map { _ in
self.users
}
.eraseToAnyPublisher()