SwiftUI 与 Combine 框架紧密集成,提供了响应式的数据流管理方案。Combine 通过发布者和订阅者模式处理异步事件和数据流。
重点:
- Combine 框架基础概念
- Publisher 和 Subscriber 的使用
- 常用操作符
- 错误处理
- 实际应用场景
Combine 基础 Link to heading
- Publisher 和 Subscriber:
// 定义发布者
let publisher = [1, 2, 3, 4, 5].publisher
// 基本订阅
publisher
.sink { completion in
print("完成: \(completion)")
} receiveValue: { value in
print("收到值: \(value)")
}
- Subject 的使用:
class DataManager {
let valuePublisher = CurrentValueSubject<Int, Never>(0)
let eventPublisher = PassthroughSubject<String, Never>()
func updateValue() {
valuePublisher.send(valuePublisher.value + 1)
}
func triggerEvent() {
eventPublisher.send("事件触发")
}
}
数据转换 Link to heading
- 基础操作符:
let numbers = [1, 2, 3, 4, 5].publisher
numbers
.map { $0 * 2 } // 转换值
.filter { $0 > 5 } // 过滤
.collect() // 收集到数组
.sink { values in
print("结果: \(values)")
}
- 组合操作符:
let publisher1 = [1, 2, 3].publisher
let publisher2 = [4, 5, 6].publisher
Publishers.CombineLatest(publisher1, publisher2)
.map { value1, value2 in
return value1 + value2
}
.sink { sum in
print("和: \(sum)")
}
异步操作处理 Link to heading
- 网络请求:
struct NetworkManager {
func fetchData() -> AnyPublisher<Data, Error> {
guard let url = URL(string: "https://api.example.com/data") else {
return Fail(error: URLError(.badURL)).eraseToAnyPublisher()
}
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.mapError { $0 as Error }
.eraseToAnyPublisher()
}
}
class ViewModel: ObservableObject {
@Published var data: Data?
private var cancellables = Set<AnyCancellable>()
func loadData() {
NetworkManager().fetchData()
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
case .finished:
print("加载完成")
case .failure(let error):
print("错误: \(error)")
}
} receiveValue: { [weak self] data in
self?.data = data
}
.store(in: &cancellables)
}
}
- 定时器:
class TimerViewModel: ObservableObject {
@Published var count = 0
private var cancellables = Set<AnyCancellable>()
func startTimer() {
Timer.publish(every: 1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
self?.count += 1
}
.store(in: &cancellables)
}
}
错误处理 Link to heading
- 错误恢复:
struct DataService {
enum DataError: Error {
case fetchFailed
case invalidData
}
func fetchData() -> AnyPublisher<String, DataError> {
Fail(error: DataError.fetchFailed)
.delay(for: 1, scheduler: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
// 使用错误恢复
DataService().fetchData()
.catch { error -> Just<String> in
// 发生错误时返回默认值
return Just("默认值")
}
.sink { value in
print("结果: \(value)")
}
- 重试机制:
struct RetryableDataService {
func fetchWithRetry() -> AnyPublisher<Data, Error> {
URLSession.shared.dataTaskPublisher(for: URL(string: "https://api.example.com")!)
.retry(3) // 最多重试3次
.map(\.data)
.mapError { $0 as Error }
.eraseToAnyPublisher()
}
}
实际应用 Link to heading
- 表单验证:
class FormViewModel: ObservableObject {
@Published var username = ""
@Published var password = ""
@Published var isValid = false
private var cancellables = Set<AnyCancellable>()
init() {
Publishers.CombineLatest($username, $password)
.map { username, password in
return username.count >= 4 && password.count >= 6
}
.assign(to: \.isValid, on: self)
.store(in: &cancellables)
}
}
- 搜索功能:
class SearchViewModel: ObservableObject {
@Published var searchText = ""
@Published var results: [String] = []
private var cancellables = Set<AnyCancellable>()
init() {
$searchText
.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
.removeDuplicates()
.filter { !$0.isEmpty }
.sink { [weak self] text in
self?.performSearch(text)
}
.store(in: &cancellables)
}
private func performSearch(_ query: String) {
// 执行搜索操作
}
}
性能考虑 Link to heading
- 内存管理:
class ResourceManager {
private var cancellables = Set<AnyCancellable>()
func subscribe() {
// 使用 weak self 避免循环引用
somePublisher
.sink { [weak self] value in
self?.process(value)
}
.store(in: &cancellables)
}
deinit {
// cancellables 会自动取消所有订阅
print("资源释放")
}
}
- 订阅限制:
class DataStreamManager {
private var cancellables = Set<AnyCancellable>()
func startStream() {
somePublisher
.buffer(size: 10, prefetch: .byRequest, whenFull: .dropOldest)
.sink { value in
// 处理数据
}
.store(in: &cancellables)
}
}
Combine 框架为 SwiftUI 提供了强大的数据流管理能力。通过发布者和订阅者模式,可以优雅地处理异步操作和状态管理。在实际开发中,合理使用 Combine 的各种操作符可以简化代码逻辑,提高应用的响应性和可维护性。