【IOS】Combine

发布时间:2026/8/18 13:28:10
【IOS】Combine 文章目录一、Combine 是什么二、核心概念三要素2.1 Publisher发布者2.2 Operator操作符2.3 Subscriber订阅者三、基础用法代码示例3.1 创建 Publisher 并订阅3.2 使用 Just sink3.3 使用 PassthroughSubject 手动发送事件3.4 使用 assign 绑定到 UI四、进阶主题4.1 网络请求URLSession.dataTaskPublisher4.2 使用 Future 替代传统闭包回调4.3 防抖Debounce—— 搜索框实战4.4 合并多个 Publisher4.5 调度器Scheduler—— 控制线程五、总结一、Combine 是什么Combine 是 Apple 在 WWDC 2019 推出的声明式响应式编程框架用于处理异步事件和数据流。它的核心思想是将随时间变化的值网络请求、UI 输入、定时器等建模为事件流通过操作符进行组合和转换。简单说Combine 让你用声明式的方式描述当数据变化时做什么而不是用嵌套闭包手动管理回调。前置知识Combine 大量使用 Swift 的泛型等高级特性建议具备中级 Swift 水平再学习。二、核心概念三要素Combine 的核心围绕三个角色展开概念作用类比Publisher发布者事件的源头产出值/错误/完成信号报社Operator操作符处理站转换/过滤/组合数据编辑部Subscriber订阅者事件的终点接收并消费数据订户数据流向Publisher → (零个或多个 Operator) → Subscriber2.1 Publisher发布者Publisher 可以发出三种东西值Values你关心的数据完成Completion.finished表示正常结束失败Failure.failure(error)表示因错误终止Publisher在没有被订阅前什么都不会做。常用内置 PublisherJust发一个值后立即完成Future异步产生一个结果成功或失败PassthroughSubject手动发送值不保留历史CurrentValueSubject手动发送值保存当前值新订阅者立即收到最新值Published属性包装器将属性变成 PublisherSwiftUI 中极常用2.2 Operator操作符操作符是 Combine 强大灵活的关键它们接收上游事件、处理后发给下游每个操作符返回一个新的 Publisher支持链式调用。常用操作符分类类别操作符作用转换map、flatMap、scan转换数据类型或结构过滤filter、compactMap、removeDuplicates按条件筛选数据合并merge、zip、combineLatest组合多个数据流时间控制debounce、throttle、delay控制事件发送时机2.3 Subscriber订阅者Subscriber 消费数据。Combine 提供两个内置订阅者sink最通用接收两个闭包——处理值的receiveValue和处理完成的receiveCompletionassign将接收到的值直接赋值给某个对象的属性如 UI 控件的text三、基础用法代码示例3.1 创建 Publisher 并订阅importCombine// 1. 创建 Publisher发布者letpublisher[1,2,3,4,5].publisher// 2. 使用 Operator 处理数据// 3. 使用 Subscriber 订阅letcancellablepublisher.filter{$0%20}// 只保留偶数.map{$0*$0}// 平方.sink(receiveCompletion:{completioninswitchcompletion{case.finished:print(流正常结束)case.failure(leterror):print(流因错误结束:\(error))}},receiveValue:{valueinprint(接收到值:\(value))// 输出: 4, 16})3.2 使用JustsinkletpublisherJust(Hello, Combine!)publisher.map{$0.uppercased()}.sink{valueinprint(value)// 输出: HELLO, COMBINE!}3.3 使用PassthroughSubject手动发送事件letsubjectPassthroughSubjectString,Never()letsubscriptionsubject.sink{valueinprint(收到:\(value))}subject.send(Hello)// 输出: 收到: Hellosubject.send(Combine)// 输出: 收到: Combinesubject.send(completion:.finished)// 发送完成信号3.4 使用assign绑定到 UIclassMyViewModel{Publishedvarusername:String}classMyViewController:UIViewController{IBOutletweakvarnameLabel:UILabel!varcancellablesSetAnyCancellable()letviewModelMyViewModel()overridefuncviewDidLoad(){super.viewDidLoad()viewModel.$username.assign(to:\.text,on:nameLabel).store(in:cancellables)// 存储订阅防止提前释放}}关键点store(in: cancellables)用于管理订阅的生命周期避免内存泄漏。四、进阶主题4.1 网络请求URLSession.dataTaskPublisherstructPost:Decodable{letid:Intlettitle:String}funcfetchPosts()-AnyPublisher[Post],Error{leturlURL(string:https://jsonplaceholder.typicode.com/posts)!returnURLSession.shared.dataTaskPublisher(for:url).map{$0.data}.decode(type:[Post].self,decoder:JSONDecoder()).eraseToAnyPublisher()// 类型擦除隐藏具体 Publisher 类型}4.2 使用Future替代传统闭包回调传统写法funcperformAsyncAction(completionHandler:escaping()-Void){DispatchQueue.main.asyncAfter(deadline:.now()2){completionHandler()}}Combine 写法funcperformAsyncActionAsFuture()-FutureVoid,Never{returnFuture{promiseinDispatchQueue.main.asyncAfter(deadline:.now()2){promise(.success(()))}}}// 使用performAsyncActionAsFuture().sink{_inprint(Future 完成)}4.3 防抖Debounce—— 搜索框实战classSearchViewModel{PublishedvarsearchTextvarcancellablesSetAnyCancellable()init(){$searchText.debounce(for:.milliseconds(500),scheduler:RunLoop.main).removeDuplicates().sink{textinprint(执行搜索:\(text))// 用户停止输入 500ms 后才触发}.store(in:cancellables)}}4.4 合并多个 Publisherletpublisher1Just(1)letpublisher2Just(2)letpublisher3Just(3)publisher1.merge(with:publisher2,publisher3).sink{print($0)}// 输出: 1, 2, 3顺序不确定4.5 调度器Scheduler—— 控制线程URLSession.shared.dataTaskPublisher(for:url).subscribe(on:DispatchQueue.global())// 在后台线程执行网络请求.receive(on:DispatchQueue.main)// 在主线程更新 UI.sink(...)五、总结学习阶段目标入门理解 Publisher、Operator、Subscriber 三要素能写简单的sink/assign订阅进阶掌握常用操作符map/filter/debounce/merge会用URLSession网络请求实战结合 SwiftUIPublishedObservableObject构建响应式应用处理复杂异步场景Combine 是 SwiftUI 数据驱动 UI 的基石掌握它之后你的异步代码将更加清晰、可维护、可组合。建议从简单的Just和PassthroughSubject开始动手练习逐步深入到网络请求和 UI 绑定场景。