【问题标题】:Combine combineLatest is not waiting for the previous operation to fire组合 combineLatest 不等待上一个操作触发
【发布时间】:2020-06-09 17:34:20
【问题描述】:

如果您在 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 { $0.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 正在处理这个问题?我在这里缺少什么?

(在我的真实代码中,有一个长时间运行的 Core Data 操作,而不是 sleep

【问题讨论】:

    标签: ios swift combine combinelatest


    【解决方案1】:

    CombineLatest 会等待,正如您正确预期的那样,但在您的情况下,getUsers 已经准备好一个值,即[];即usersgetUsers 运行时是什么。

    您实际上并不需要使用CombineLatest 来“等待”直到某些异步操作发生。你可以只链接发布者:

    return importUsers()
               .setFailureType(to: Error.self)
               .flatMap { _ in
                   getUsers()
               }
               .eraseToAnyPublisher()
    

    事实上,getUsers 甚至都不需要,如果您可以假设 usersimportUsers 之后填充:

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

    【讨论】:

    • 你是对的。有趣的是,如果我创建一个变量 let users = getUsers() 并在 if 这不起作用的两个分支中使用它。我想这是因为当我创建 let users = getUsers() 时,它的值已经是 []
    • 是的。我认为您对这个问题和以前的问题的困惑源于Future 这个词——它实际上不会在“异步”未来发生——它可能会发生,但这完全取决于何时设置承诺。否则,它只会在运行时复制该值。所以你的getUsers 也可能是func getUsers() { Just(users) }(加上失败类型设置)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    • 2018-05-13
    • 2019-04-02
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多