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

2024-03-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。

上一篇 下一篇

猜你喜欢

热点阅读