Combine 基本使用指南
Combine 是 Apple 在 2019 年推出的响应式编程框架,用于处理随时间变化的值流。下面是 Combine 的基本概念和使用方法。
核心概念
1. Publisher(发布者)
- 产生值的源头
- 可以发送 0 个或多个值
- 可能以完成或错误结束
2. Subscriber(订阅者)
- 接收来自 Publisher 的值
- 可以控制数据流的需求
3. Operator(操作符)
- 转换、过滤、组合来自 Publisher 的值
基本使用示例
创建简单的 Publisher
swift
import Combine
// 1. Just - 发送单个值然后完成
let justPublisher = Just("Hello, World!")
// 2. Sequence - 发送序列中的值
let sequencePublisher = [1, 2, 3, 4, 5].publisher
// 3. Future - 异步操作的结果
func fetchData() -> Future<String, Error> {
return Future { promise in
// 模拟异步操作
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
promise(.success("Data fetched"))
}
}
}
// 4. @Published 属性包装器
class DataModel {
@Published var name: String = "Initial"
}
订阅 Publisher
swift
// 使用 sink 订阅
var cancellables = Set<AnyCancellable>()
// 订阅 Just
justPublisher
.sink { value in
print("Received value: \(value)")
}
.store(in: &cancellables)
// 订阅 Sequence
sequencePublisher
.sink(
receiveCompletion: { completion in
switch completion {
case .finished:
print("Finished successfully")
case .failure(let error):
print("Failed with error: \(error)")
}
},
receiveValue: { value in
print("Received: \(value)")
}
)
.store(in: &cancellables)
常用操作符
swift
// 转换操作符
sequencePublisher
.map { $0 * 2 } // 转换每个值
.filter { $0 > 5 } // 过滤值
.reduce(0, +) // 聚合值
.sink { print("Result: \($0)") }
.store(in: &cancellables)
// 组合操作符
let publisher1 = [1, 2, 3].publisher
let publisher2 = ["A", "B", "C"].publisher
Publishers.Zip(publisher1, publisher2)
.sink { print("Zipped: \($0), \($1)") }
.store(in: &cancellables)
// 错误处理
enum MyError: Error {
case testError
}
Fail(outputType: String.self, failure: MyError.testError)
.catch { error in
Just("Recovered from error")
}
.sink { print($0) }
.store(in: &cancellables)
处理 UI 更新
swift
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var button: UIButton!
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
setupBindings()
}
private func setupBindings() {
// 监听文本框变化
NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: textField)
.compactMap { ($0.object as? UITextField)?.text }
.sink { [weak self] text in
self?.label.text = "You typed: \(text)"
}
.store(in: &cancellables)
// 按钮点击事件
button.publisher(for: .touchUpInside)
.sink { [weak self] _ in
self?.handleButtonTap()
}
.store(in: &cancellables)
}
private func handleButtonTap() {
print("Button tapped!")
}
}
网络请求示例
swift
struct User: Codable {
let id: Int
let name: String
let email: String
}
class UserService {
private var cancellables = Set<AnyCancellable>()
func fetchUsers() -> AnyPublisher<[User], Error> {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
return Fail(error: URLError(.badURL))
.eraseToAnyPublisher()
}
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: [User].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
func loadUsers() {
fetchUsers()
.receive(on: DispatchQueue.main) // 切换到主线程
.sink(
receiveCompletion: { completion in
switch completion {
case .finished:
print("Request completed")
case .failure(let error):
print("Error: \(error)")
}
},
receiveValue: { users in
print("Received users: \(users)")
}
)
.store(in: &cancellables)
}
}
定时器示例
swift
class TimerExample {
private var cancellables = Set<AnyCancellable>()
func startTimer() {
Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.sink { [weak self] date in
print("Timer fired at: \(date)")
self?.handleTimerTick()
}
.store(in: &cancellables)
}
private func handleTimerTick() {
// 处理定时器触发
}
}
内存管理
swift
class MyViewController: UIViewController {
private var cancellables = Set<AnyCancellable>()
deinit {
// 自动取消所有订阅
cancellables.forEach { $0.cancel() }
}
}
最佳实践
- 及时取消订阅 :使用
store(in:)管理订阅生命周期 - 线程切换 :使用
receive(on:)在合适的线程处理数据 - 错误处理 :合理使用
catch、replaceError等操作符 - 避免强引用循环 :在闭包中使用
[weak self]
这些是 Combine 的基本使用方法。Combine 提供了强大的响应式编程能力,特别适合处理异步事件流和数据绑定。