首页 > 解决方案 > Swift 合并条件 FlatMap 结果

问题描述

使用 Swift Combine 时如何为 flatMap 提供不同的返回类型?我有我的第一个发布者,它发出一个值,然后我 flatMap 将其转换为一个新的发布者。但是,根据原始值,我可能需要一个不同的发布者来返回不同的类型。

我在下面添加了一个基本示例。

import Combine


class Testing{
    var subscriptions = Set<AnyCancellable>()
    
    
    func getTestScore()->AnyPublisher<Int, Never>{
        return Just(80).eraseToAnyPublisher()
    }
    
    func congratulate()->AnyPublisher<String, Never>{
        return Just("Good Job!").eraseToAnyPublisher()
    }
    
    func getGPA()->AnyPublisher<Double, Never>{
        return Just(2.2).eraseToAnyPublisher()
    }
    
    init() {
        getTestScore()
            .flatMap{ score in
                if score < 70{
                    return self.getGPA()
                } else{
                    return self.congratulate()
                }
            }
            .sink { _ in } receiveValue: { value in
                print(value)
            }.store(in: &subscriptions)
    }
}

let testing = Testing()

标签: swiftconditional-statementscombineflatmap

解决方案


正如 New Dev 所说,返回条件数据类型是不可能的——除非你不想将类型擦除为Any.

我的建议是创建一个专门的发布者,如果分数超过(或低于)某个限制,它就会发出。现在使用您的新发布者创建两个单独的、类型安全的管道。我知道您要求只使用一个管道。但是,我认为这种方法会给您带来更多好处。

请在下面找到我的工作示例:

import Combine

class Testing{
    var subscriptions = Set<AnyCancellable>()
    
    func getTestScore()->AnyPublisher<Int, Never> {
        return Just(80).eraseToAnyPublisher()
    }
    
    func congratulate()->AnyPublisher<String, Never> {
        return Just("Good Job!").eraseToAnyPublisher()
    }
    
    func getGPA()->AnyPublisher<Double, Never> {
        return Just(2.2).eraseToAnyPublisher()
    }
    
    init() {
        let scoreExceedsLimit: AnyPublisher<Bool, Never> = getTestScore()
            .map { $0 >= 70 }
            .eraseToAnyPublisher()
        
        scoreExceedsLimit
            .filter { $0 == true }
            .flatMap { _ in self.congratulate() }
            .sink(receiveValue: { value in
                print("first pipeline: \(value)")
            })
            .store(in: &subscriptions)
        
        scoreExceedsLimit
            .filter { $0 == false }
            .flatMap { _ in self.getGPA() }
            .sink(receiveValue: { value in
                print("second pipeline: \(value)")
            })
            .store(in: &subscriptions)
    }
}

let testing = Testing()

推荐阅读