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,如果您可以假设 usersimportUsers 之后填充:

return importUsers()
           .map { _ in
               self.users
           }
           .eraseToAnyPublisher()