美文网首页
Combine 异步事件流的组合和处理

Combine 异步事件流的组合和处理

作者: 大成小栈 | 来源:发表于2024-03-03 21:03 被阅读0次

    这段代码是Swift语言中的一段使用Combine框架的代码,主要用于处理异步事件流的组合和处理。

    /// 创建一个合并请求
    private(set) lazy var combine = CombineAction<String?, (CreateConfigModel?, DetailModel?), APIError> { [unowned self] input in
                let detailSignal = PhotoTalkApi.shared.publisher(.detail, type: JSON.self)
                    .tryMap({
                        if let data = try? $0.result?.rawData() {
                            AppDatabase.shared[.talkingDetailData] = data
                            return DetailModel.decode(with: data)
                        } else {
                            throw APIError.undefined
                        }
                    }).mapError({
                        APIError(error: $0)
                    }).eraseToAnyPublisher()
                
                guard let input else {
                    return detailSignal
                        .map({ (nil, $0) }).eraseToAnyPublisher()
                }
                
                let tagSignal = PhotoTalkApi.shared.publisher(.toolTags(route: "phototalk://page/creator/detail?type=\(input)"), type: JSON.self)
                    .tryMap({
                        if let data = try? $0.result?.rawData() {
                            AppDatabase.shared[.talkingConfigData(input)] = data
                            return CreateConfigModel.decode(with: data)
                        } else {
                            throw APIError.undefined
                        }
                    }).mapError({
                        APIError(error: $0)
                    })
                    .eraseToAnyPublisher()
                
                return tagSignal.combineLatest(detailSignal)
                    .eraseToAnyPublisher()
            }
    
    ----------------------------------------------------------------
    
    /// 详情数据 + 配置数据
     combine.values
        .prepend((configModel, detailModel))
        .sink(receiveValue: { [weak self] tuple in
            guard let self else { return }
            // ...
        }).store(in: &cancellables)
    /// 错误处理
    combine.errors
        .receive(on: DispatchQueue.main)
        .sink(receiveValue: { [weak self] error in
           // ...
        }).store(in: &cancellables)
    
    /// 发起请求
    if type == // ... {
        combine.execute(nil)
    } else {
        combine.execute(type.value)
    }
    

    下面是对代码的详细解读:

    private(set) lazy var combine:这是一个懒加载的属性,其类型是CombineAction<String?, (CreateConfigModel?, DetailModel?), APIError>。这个属性使用了private(set),表示在类内部可以读写,但在外部只能进行读取操作。

    CombineAction:这是一个自定义的Combine操作符,用于将两个不同类型的Publisher合并到一个Publisher中。它的泛型参数分别是输入类型(String?)、输出类型((CreateConfigModel?, DetailModel?))和错误类型(APIError)。

    [unowned self]:这是一个捕获列表,用于避免循环引用。在Combine中,由于可能存在长时间的订阅,需要小心避免循环引用问题。

    let detailSignal = ...:这里创建了一个名为detailSignal的Publisher,用于处理获取详细信息的API请求。具体步骤包括:

    使用PhotoTalkAPI.shared.publisher创建一个Publisher,订阅了一个名为.detail的API端点,并指定返回类型为JSON。
    使用tryMap操作符处理API的结果,将原始数据存储到本地数据库中,然后通过DetailModel.decode将数据解码为DetailModel。
    使用mapError操作符将可能的错误映射为APIError。
    使用eraseToAnyPublisher将整个操作链转换为AnyPublisher类型。
    guard let input else { ... }:这是一个guard语句,用于检查输入是否为nil。如果输入为nil,则直接返回detailSignal的Publisher,其中使用map将输出映射为(nil, $0)。

    let tagSignal = ...:这里创建了一个名为tagSignal的Publisher,用于处理获取标签信息的API请求。具体步骤与detailSignal类似。

    return tagSignal.combineLatest(detailSignal):使用combineLatest操作符将tagSignal和detailSignal两个Publisher的最新值进行组合,生成一个新的Publisher,其输出类型为元组(CreateConfigModel?, DetailModel?)。

    .eraseToAnyPublisher():最后,通过eraseToAnyPublisher将整个操作链转换为AnyPublisher类型,以符合combine属性的类型要求。

    eraseToAnyPublisher 的作用:eraseToAnyPublisher 是 Combine 框架中的一个操作符,其主要作用是将一个具体类型的 Publisher 转换为 AnyPublisher 类型。在 Combine 中,AnyPublisher 是一个类型擦除的抽象,用于隐藏底层具体类型,使其更加通用和灵活。

    Combine 中的 Publisher 类型是泛型的,它包含了特定的输出类型和错误类型。在某些情况下,你可能想要隐藏具体类型的 Publisher,以便在 API 的设计或函数签名中更加灵活,不暴露太多实现细节。

    这是 eraseToAnyPublisher 的一些关键作用:

    类型擦除:将一个具体类型的 Publisher 转换为 AnyPublisher,隐藏了底层具体类型,使其在 API 设计中更加通用。

    接口灵活性:通过返回 AnyPublisher,可以更轻松地适应接受 Publisher 参数的函数或方法,而无需暴露太多的具体实现细节。

    错误处理:AnyPublisher 会擦除具体的错误类型,将其统一为 Swift 的 Error 类型,这可以使错误处理更加灵活,不需要关心具体的错误类型。

    示例代码中使用了 eraseToAnyPublisher 主要是为了符合 combine 属性的声明,因为该属性的类型是 CombineAction<String?, (CreateConfigModel?, DetailModel?), APIError>,而 combineLatest 操作返回的 Publisher 的具体类型可能是其他类型,为了满足类型的匹配,使用了 eraseToAnyPublisher 进行类型擦除。这使得 combineLatest(detailSignal, tagSignal) 的返回值变成了 AnyPublisher<(CreateConfigModel?, DetailModel?), APIError>,适应了 combine 属性的声明。

    总体而言,这段代码的主要功能是通过Combine框架处理两个异步API请求,将它们的结果合并为一个Publisher,并在最后将整个操作链包装成一个懒加载的属性combine。

    相关文章

      网友评论

          本文标题:Combine 异步事件流的组合和处理

          本文链接:https://www.haomeiwen.com/subject/avhlzdtx.html