swift 访问在合并链的顶部创建的发布者

mtb9vblg  于 2023-03-22  发布在  Swift
关注(0)|答案(2)|浏览(114)

我试图创建一个函数,它将返回一个结构体,该结构体是由合并调用链中的两个发布者构造的,类似于下面的伪代码

struct UpdatedPilotsInfo {
    let pilots: [JSON]
    let squad: JSON
}

func buildInfoIdeal() {
        func processPilots(squad: JSON) -> AnyPublisher<[JSON] , XWSImportError> { ... }
        func loadSquad() -> AnyPublisher<JSON, XWSImportError> { ... }
        
        let squadInfoPublisher: AnyPublisher<(JSON, [JSON]), XWSImportError> = JSONSection
            .SquadService_XWSImport_New
            .SquadService
            .loadSquad() // AnyPublisher<JSON, XWSImportError>
            .flatMap(processPilots) // AnyPublisher<[JSON], XWSImportError>
            .???    // AnyPublisher<(JSON, [JSON]), XWSImportError>
            .map{ tuple -> UpdatedPilotsInfo in
                return UpdatedPilotsInfo(squad: tuple.0, pilots: tuple.1)
            }.eraseToAnyPublisher()
}

我的问题是,我不知道如何才能让一个上游出版商创建在链的顶端(loadSquad)。在上面的示例中,我将loadSquad()的输出传递给processPilots(),并希望根据loadSquad()processPilots()的结果构建UpdatedPilotsInfo。我想我可以通过执行以下操作来实现这一点,但我希望使用一个简单的链来代替所有这些代码:

func buildInfo() -> AnPublisher<UpdatedPilotsInfo, XWSImportError> {
        func processPilots(squad: JSON) -> AnyPublisher<[JSON] , XWSImportError> { ... }
        func loadSquad() -> AnyPublisher<JSON, XWSImportError> { ... }
        
        let squadPublisher: AnyPublisher<JSON, XWSImportError> = JSONSection
            .SquadService_XWSImport_New
            .SquadService
            .loadSquad() // AnyPublisher<JSON, XWSImportError>
            .eraseToAnyPublisher()

        let updatedPilots: AnyPublisher<[JSON], XWSImportError> = squadPublisher
            .flatMap{ [weak self] squad -> AnyPublisher<[JSON], XWSImportError in
                let s = self
                return s.processPilots(squad)
            }
            .eraseToAnyPublisher()

        let zip = Publishers.Zip(squadPublisher, updatedPilots)
            .eraseToAnyPublisher()  // AnyPublisher<(JSON, [JSON]), XWSImportError>

        return zip.map{ tuple -> UpdatedPilotsInfo in 
            return UpdatedPilotsInfo(squad: tuple.0, pilots: tuple.1)
        }.eraseToAnyPublisher() 
    }

这是我可以用现有的操作符完成的,还是我需要创建一个自定义操作符?

q3qa4bjr

q3qa4bjr1#

据我所知,你有两个发布器,你想把它们组合起来,这样当两个发布器都收到输出时,一个结构就被创建了?
我试图在Playground中创建一个与您的问题非常相似的示例。

typealias JSON = Int
typealias XWSImportError = Error

// Just for simulation.
func processPilots() -> AnyPublisher<[JSON] , XWSImportError> {
    Just<[JSON]>([1, 2, 3]).setFailureType(to: XWSImportError.self).eraseToAnyPublisher()
}

func loadSquad() -> AnyPublisher<JSON, XWSImportError> {
    Just<JSON>(4).setFailureType(to: XWSImportError.self).eraseToAnyPublisher()
}

struct UpdatedPilotsInfo {
    let pilots: [JSON]
    let squad: JSON
}

// Simpler solution
func buildInfoIdeal() -> AnyPublisher<UpdatedPilotsInfo, XWSImportError> {
    processPilots()
        .zip(loadSquad())
        .map { UpdatedPilotsInfo(pilots: $0.0, squad: $0.1) }
        .eraseToAnyPublisher()
}

// Test
let subscription = buildInfoIdeal()
    .sink(receiveCompletion: { completion in
        // Handle a completion.
    }, receiveValue: { value in
        print(value)
    })

// Calling order doesn't matter.
// The result is always the same: UpdatedPilotsInfo(pilots: [1, 2, 3], squad: 4)
processPilots()
loadSquad()

希望我能帮到你。

ldfqzlk8

ldfqzlk82#

请记住,.flatMap { Just($0) }.map { $0 }是完全相同的,而且都是无操作的。
这意味着您可以使用传递参数,同时将其与其他执行某些实际工作的发布者组合。

loadSquad
    .flatMap { Publishers.Zip(Just($0).setFailureType(to: Error.self), processPilots($0)) }
    .map { UpdatedPilotsInfo(squad: $0.0, pilots: $0.1) }
    .eraseToAnyPublisher()

因此,通过上面的操作,我们将来自loadSquad的响应与来自flatMap内部的processPilots的响应一起传递。

相关问题