文章目录
- [📘 Combine 框架完整指南(含示例代码 + 实战)](#📘 Combine 框架完整指南(含示例代码 + 实战))
- 一、核心概念
- 二、基础示例
- [三、常用 Publisher](#三、常用 Publisher)
- 四、操作符
- 五、输入优化(完整实战)
-
- ViewModel
- [SwiftUI 页面](#SwiftUI 页面)
- 六、按钮防重复点击(完整实战)
-
- ViewModel
- [SwiftUI 页面](#SwiftUI 页面)
- 七、网络请求
- 八、内存管理
- 九、总结
- [🚀 一句话](#🚀 一句话)
- [十、输入框 + 网络请求 + 自动取消(高级🔥)](#十、输入框 + 网络请求 + 自动取消(高级🔥))
-
- 核心思路
- [ViewModel 实现](#ViewModel 实现)
📘 Combine 框架完整指南(含示例代码 + 实战)
一、核心概念
Combine 是 Apple 的响应式编程框架:
Publisher → Operator → Subscriber
二、基础示例
swift
import Combine
let cancellable = Just(5)
.map { $0 * 2 }
.sink { print($0) } // 10
三、常用 Publisher
Just
swift
Just("Hello")
.sink { print($0) }
Future
swift
Future<String, Error> { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
promise(.success("完成"))
}
}
.sink(receiveCompletion: { _ in },
receiveValue: { print($0) })
PassthroughSubject
swift
let subject = PassthroughSubject<String, Never>()
subject.sink { print($0) }
subject.send("事件1")
CurrentValueSubject
swift
let subject = CurrentValueSubject<Int, Never>(0)
subject.sink { print($0) }
subject.send(1)
四、操作符
swift
Just(10)
.map { $0 * 2 }
.filter { $0 > 10 }
.sink { print($0) }
五、输入优化(完整实战)
ViewModel
swift
import Combine
import SwiftUI
class SearchViewModel: ObservableObject {
@Published var keyword: String = ""
private var cancellables = Set<AnyCancellable>()
init() {
$keyword
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.removeDuplicates()
.filter { !$0.isEmpty }
.filter { $0.count > 2 }
.sink { [weak self] value in
self?.search(keyword: value)
}
.store(in: &cancellables)
}
func search(keyword: String) {
print("发起搜索:", keyword)
}
}
SwiftUI 页面
swift
struct SearchView: View {
@StateObject var vm = SearchViewModel()
var body: some View {
TextField("输入搜索", text: $vm.keyword)
.textFieldStyle(.roundedBorder)
.padding()
}
}
六、按钮防重复点击(完整实战)
ViewModel
swift
import Combine
class ButtonViewModel {
let tapSubject = PassthroughSubject<Void, Never>()
private var cancellables = Set<AnyCancellable>()
init() {
tapSubject
.throttle(for: .seconds(1), scheduler: RunLoop.main, latest: false)
.sink { [weak self] in
self?.handleTap()
}
.store(in: &cancellables)
}
func handleTap() {
print("按钮点击处理")
}
}
SwiftUI 页面
swift
struct ButtonView: View {
let vm = ButtonViewModel()
var body: some View {
Button("点击") {
vm.tapSubject.send(())
}
}
}
七、网络请求
swift
struct User: Decodable {
let name: String
}
func fetchUser() -> AnyPublisher<User, Error> {
let url = URL(string: "https://api.example.com/user")!
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: User.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
八、内存管理
swift
var cancellables = Set<AnyCancellable>()
publisher
.sink { _ in }
.store(in: &cancellables)
九、总结
- debounce → 输入优化
- throttle → 防止重复点击
- Future → 异步封装
- AnyPublisher → 类型擦除
🚀 一句话
Combine = 用数据流方式写异步代码
十、输入框 + 网络请求 + 自动取消(高级🔥)
核心思路
ViewModel 实现
swift
class AdvancedSearchViewModel: ObservableObject {
@Published var keyword: String = ""
@Published var results: [User] = []
@Published var isLoading: Bool = false
private let network = NetworkService()
private var cancellables = Set<AnyCancellable>()
init() {
$keyword
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.removeDuplicates()
.filter { !$0.isEmpty }
.map { [weak self] keyword -> AnyPublisher<[User], Never> in
guard let self = self else {
return Just([]).eraseToAnyPublisher()
}
self.isLoading = true
return self.network.searchUser(keyword: keyword)
.catch { _ in Just([]) }
.handleEvents(receiveCompletion: { _ in
self.isLoading = false
})
.eraseToAnyPublisher()
}
.switchToLatest()
.receive(on: RunLoop.main)
.sink { [weak self] users in
self?.results = users
}
.store(in: &cancellables)
}
}