本文目录导读:

- 案例 1:基础用法(并行请求合并)
- 案例 2:等待两个异步网络请求(Combine 标准写法)
- 案例 3:RxSwift 中的 thenCombine(如果你需要对比)
- 核心总结(面试重点)
- 延伸:与
zip的区别(高频考点)
在 Swift 并发编程中,thenCombine 是 Combine 框架中的一个核心操作符,它的作用是将两个 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,如果你之前用过 RxSwift,thenCombine 是 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 标准写法)
这个是完整的实际业务场景,使用了 URLSession 和 Future。
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 |
combineLatest 或 thenCombine(用于指定 pair) |
| 作用 | 两个 Publisher 都发出新值时,合并成一个元组 | 同左 |
| 触发时机 | 只要其中任何一个 Publisher 发出新值,下游就会触发一次 | 同左 |
| 计数 | 总是返回最新的两个值 | 同左 |
注意陷阱:
combineLatest会等待两个 Publisher 都发出第一个值后,才会第一次触发下游。- 如果其中一个 Publisher 发出多个值,它只保留最新的值,直到另一个也发出新值,才组合。
- 错误处理:如果其中任何一个 Publisher 发出错误(
Failure),整个CombineLatest会立即终止并发送错误。
延伸:与 zip 的区别(高频考点)
你可能会被追问:“combineLatest 和 zip 有什么区别?”
combineLatest:每次任意一方发出新值,就立即取当前双方的最新值合并,适合“天气温度和湿度同时变化”的场景。zip:严格配对,双方必须按顺序一一对应,当 A 发出第 1 个值,B 也发出第 1 个值,才组合;然后等待 A 第 2 个值和 B 第 2 个值,如果一方发了很多,另一方没发,就不会触发,适合“下载文件和写日志同时完成”的场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播