一个新事物的呈现,首先要简单了解基本概念,由理论出发到实践查验,再经由实践得出理论
概念
Combine
Customize handling of asynchronous events by combining event-processing operators.
- 自定义处理异步事情
- 通过把事情组合处理
- 简单了解这些就够了,接下来看实践,再由实践得出更多的理论
实践
事例一
有这样两个页面
- 老师发布作业的页面,名称和班级是必填的,直接影响到底部发布按钮的点击状况
- 学生提交作业的页面,文字和图片必选其一,每个改动都会影响到底部提交按钮的状况
方案 一
正常情况下咱们的完成逻辑是
- 一个 ViewController 持有两个 SubView,一个 ActionBtn,subView 的内容改动,回调通知(block、delegate、notification)到 ViewController,然后改动 ActionBtn 的状况
- 为了复用和解耦,咱们会给 subView 增加一个逻辑处理类 (handler、viewModel、presenter)来处理 view 里面控件逻辑
- 终究点击按钮的时分,封装数据发送恳求到服务
- 如图所示,model 层在这样的流程中毫无用武之地,一起回调太多也会导致代码繁琐和维护困难
- 究其原因在于,1. 异步,2 组合,
- 假如只要一个 view,运用异步回调牵强还能够接受
假如都放在 VC 里面同步处理,远古写法就算了
方案二
运用 Combine
-
一个 ViewController 持有两个 SubView,一个 ActionBtn,一个Model,把 Model 传递到 SubView 中,所有 SubView 的内容更改,都是对 Model 的特点的更改
-
ViewController 监听 Model 特点的改动,一起改动 ActionBtn 的状况,或许直接把 Btn 的状况绑定到特点上
-
点击按钮,把 Model 直接传递进去进行网络恳求
-
明面上咱们只是增加了 Model 层,运用监听来替代回调,但实际上他们有本质的不同,请看代码:
/// 发布、上传 作业对应的 Model public class CreateModel { /// 标题 @Published public var title: String = "" /// 班级 ID @Published public var classID: String = "" /// 是否能够发布 public var validCreateTask: AnyPublisher<Bool, Never> { return Publishers.CombineLatest($title, $classID) .map { (title, classID) in return !title.isEmpty && !classID.isEmpty }.eraseToAnyPublisher() } } class CreateTaskViewController: UIViewController { override func viewDidLoad() { workModel.validCreateTask .assign(to: \.isEnabled, on: self.actionBtn) .store(in: &cancellSet) } }
-
依据体系的 Combine 库,咱们能够用更少、更简洁的代码做到异步处理和组合处理,这也是 Combine 的含义地点
事例二
照例先看一个页面需求
-
依据选中个数,顶部导航栏展现全选和取消全选,底部按钮展现是否可点击和数字
这次咱们直接运用 Combine 的方案,
- 一个 ViewController 持有 TableView,NaviView,BottomView
- 一个统一的数据源 DataModel,由 Model 层处理所有的数据逻辑
- ViewController 和 SubViews 依据数据改动进行界面展现
class DataModel { var totalList: [ItemModel] = [] @Published var isEditStatus: Bool = false @Published var selectedList: [ItemModel] = [] } extension DataModel { /// 数据改动 var dataChanged: AnyPublisher<([ItemModel], Bool), Never> { return Publishers.CombineLatest($selectedList, $isEditStatus) .eraseToAnyPublisher() } /// 是否全选 var isFullSelected: Bool { return selectedList.count >= totalList.count } // add // remove // contain // selecteAll // unSelecteAll }
小结
- 上面的两个例子,如同跟咱们平常的代码逻辑有些改动,又如同没有改动
- 他们本质上到底有哪些不同?
理论
The Combine framework provides a declarative Swift API for processing values over time
- Combine 提供了一套声明式的 Swift API,用来处理随时刻改动的 Values
- Combine 是苹果官方的一个 Swift 呼应式编程 结构,是一种面向数据流和改动传播的 声明式编程范式
- 而呼应式编程,比较熟悉的有 RxSwift,ReactiveCocoa等,Combine 跟他们相同,都用了大量的函数式 编程的写法
函数式编程:
- Swift 的高阶函数,reduce,map 等都属于函数式编程
- 简单说便是把运算进程尽可能写成一系列【嵌套】的函数调用,而不是一行行的办法履行
- 而要完成这种方式就要尽可能的运用【表达式】,而不是【履行句子】
- 举个:
// 数字1、2 的和是3 sum(1, 2) = 3 // 数字 1 加 2 等于3 1 + 2 = 3
声明式编程:
-
简单理解下面两句话:
1. View 上新增一个 Label,它的字体大小是 16,文字是 "label",字体颜色是黑色(指令/指令式句子) 2. View 上新增一个字体大小是 16,文字是 "label",字体颜色是黑色的 Label(描述性句子)
-
再看开发进程中最常用的 TableViewCell,直接设置特点的方式在逐渐的被声明式的特点替换
-
-
指令/指令式编程更多的告知计算机怎么做,How to do,面向的是进程,一步步履行
-
声明式编程更多的是做什么,What to do,要的是一个结果
小结
- 运用 Combine 不仅仅使得代码清晰,逻辑简洁,便利维护,更多的是编程思维的一个碰撞和改动,学习呼应式编程,这是一个非常好的切入点。
- 尤其 Combine 是内置在 Apple 体系的,对 App包体积毫无影响,对比 RxSwift 的性能也更好。
- 跟着体系更新,咱们不可避免的要接触和学习 SwiftUI,Combine 更是必不可少。
- 一家之谈,仅抛砖引玉,欢迎交流。