thenCombine案例

wen java案例 2

本文目录导读:

thenCombine案例

  1. 案例 1:基础用法(并行请求合并)
  2. 案例 2:等待两个异步网络请求(Combine 标准写法)
  3. 案例 3:RxSwift 中的 thenCombine(如果你需要对比)
  4. 核心总结(面试重点)
  5. 延伸:与 zip 的区别(高频考点)

在 Swift 并发编程中,thenCombineCombine 框架中的一个核心操作符,它的作用是将两个 Publisher 的最新值组合成一个元组,当两个 Publisher 都发出新值时,才会触发下游。

这在处理多个独立异步请求(如并行加载用户信息和用户头像)时非常有用。

以下是几个由浅入深的案例:


案例 1:基础用法(并行请求合并)

场景:同时请求“用户信息”和“用户设置”,都成功后,将结果整合展示。

import Combine
import Foundation
// 模拟网络请求1:获取用户信息
func fetchUserInfo() -> AnyPublisher<String, Never> {
    return Future<String, Never> { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
            promise(.success("张三,年龄28"))
        }
    }
    .eraseToAnyPublisher()
}
// 模拟网络请求2:获取用户设置
func fetchUserSettings() -> AnyPublisher<String, Never> {
    return Future<String, Never> { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1.5) {
            promise(.success("深色模式,语言:中文"))
        }
    }
    .eraseToAnyPublisher()
}
// 核心代码:
func loadUserProfile() {
    // 1. 发起两个异步请求
    let publisher1 = fetchUserInfo()
    let publisher2 = fetchUserSettings()
    // 2. 使用 thenCombine 合并
    let cancellable = publisher1
        .combineLatest(publisher2) // 错误写法?不,下面是正确写法
        .sink { info, settings in
            print("合并结果:\(info) —— \(settings)")
        }
    // 注意:Combine 中正确写法是 combineLatest,但面试常问 thenCombine 在 RxSwift 中的对应。
    // 在 Combine 中,对应的操作符就是 combineLatest。
}

重要澄清:在 Swift Combine 中,并没有名为 thenCombine 的操作符。Combine 使用的是 combineLatest,如果你之前用过 RxSwiftthenCombine 是 RxSwift 的操作符,在 Combine 中,职责相同的是 combineLatest

下面是 Combine 的实际写法

import Combine
let pub1 = Just("Hello")
let pub2 = Just("World")
let cancellable = pub1
    .combineLatest(pub2)
    .sink { value1, value2 in
        print("\(value1) \(value2)") // 输出:Hello World
    }

案例 2:等待两个异步网络请求(Combine 标准写法)

这个是完整的实际业务场景,使用了 URLSessionFuture

import Combine
import UIKit
// 模拟两个不同的 API 端点
enum API {
    static func requestUser() -> AnyPublisher<UserModel, Error> {
        let url = URL(string: "https://api.example.com/user")!
        return URLSession.shared.dataTaskPublisher(for: url)
            .map(\.data)
            .decode(type: UserModel.self, decoder: JSONDecoder())
            .eraseToAnyPublisher()
    }
    static func requestOrders() -> AnyPublisher<[OrderModel], Error> {
        let url = URL(string: "https://api.example.com/orders")!
        return URLSession.shared.dataTaskPublisher(for: url)
            .map(\.data)
            .decode(type: [OrderModel].self, decoder: JSONDecoder())
            .eraseToAnyPublisher()
    }
}
// 视图模型中使用
class ProfileViewModel: ObservableObject {
    @Published var user: UserModel?
    @Published var orders: [OrderModel] = []
    @Published var isLoading = false
    private var cancellables = Set<AnyCancellable>()
    func loadData() {
        isLoading = true
        // 关键:同时请求,等待两者都完成再处理
        API.requestUser()
            .combineLatest(API.requestOrders()) // 相当于 RxSwift 的 thenCombine
            .sink { completion in
                self.isLoading = false
                switch completion {
                case .finished: break
                case .failure(let error):
                    print("加载失败: \(error)")
                }
            } receiveValue: { user, orders in
                self.user = user
                self.orders = orders
                print("数据全部加载完成:\(user.name) 有 \(orders.count) 个订单")
            }
            .store(in: &cancellables)
    }
}

案例 3:RxSwift 中的 thenCombine(如果你需要对比)

如果你面试或维护的旧项目使用的是 RxSwift,那么代码长这样:

import RxSwift
import RxCocoa
let disposeBag = DisposeBag()
// 两个 Observable
let username = BehaviorSubject<String>(value: "尚未输入") // 模拟用户名输入
let passwordLength = BehaviorSubject<Int>(value: 0) // 模拟密码长度
// thenCombine 的用法
Observable
    .combineLatest(username, passwordLength) // 注意:这里就是 combineLatest
    .map { name, length in
        return "用户名是 \(name),密码长度为 \(length)"
    }
    .subscribe(onNext: { text in
        print(text)
    })
    .disposed(by: disposeBag)
// 模拟输入变化
username.onNext("John")
passwordLength.onNext(8)
// 输出:用户名是 John,密码长度为 8

核心总结(面试重点)

特性 Combine RxSwift
操作符名称 combineLatest combineLatestthenCombine(用于指定 pair)
作用 两个 Publisher 都发出新值时,合并成一个元组 同左
触发时机 只要其中任何一个 Publisher 发出新值,下游就会触发一次 同左
计数 总是返回最新的两个值 同左

注意陷阱

  1. combineLatest等待两个 Publisher 都发出第一个值后,才会第一次触发下游。
  2. 如果其中一个 Publisher 发出多个值,它只保留最新的值,直到另一个也发出新值,才组合。
  3. 错误处理:如果其中任何一个 Publisher 发出错误(Failure),整个 CombineLatest 会立即终止并发送错误。

延伸:与 zip 的区别(高频考点)

你可能会被追问:“combineLatestzip 有什么区别?”

  • combineLatest每次任意一方发出新值,就立即取当前双方的最新值合并,适合“天气温度和湿度同时变化”的场景。
  • zip严格配对,双方必须按顺序一一对应,当 A 发出第 1 个值,B 也发出第 1 个值,才组合;然后等待 A 第 2 个值和 B 第 2 个值,如果一方发了很多,另一方没发,就不会触发,适合“下载文件和写日志同时完成”的场景。

上一篇allOf案例

下一篇thenApply案例

抱歉,评论功能暂时关闭!