作者简介
青花瓷的平方,携程技术专家,主要从事无线开发,负责携程支付iOS相关开发工作。
一、引言
Combine.framework 是Apple在2019 WWDC 上基于Swift推出的函数响应框架(Functional Reactive Programming),支持Apple全平台的操作系统(iOS13+,macOS 10.15+等)。函数式响应框架无论在哪个平台早已流行泛滥,开源的Rx更是实现了各种语言的响应式编程框架。Apple在这个时候推出响应式框架,无疑是对自己护城河的进一步巩固。事实上SwiftUI的数据驱动就是依赖Combine。
本文将深入浅出地介绍Combine的基本概念和原理,然后通过具体demo详细阐述其在实际编码中的应用。
二、什么是Combine
Combine is Swift declarative framework for processing values over time
Combine 为处理随着时间变化的值的一种声明式框架。Combine 作用是将异步事件通过组合事件处理操作符进行自定义处理。关注如何处理变化的值,正是响应式编程的核心。
Combine可以概述为一种声明式的函数响应式编程,简洁用下图表示:
通过此图,我们可以总结Combine是什么:
Combine = Publishers + Operators + Subscribers
2.1 Publishers
Publisher sends sequences of values over time to one or more Subscribers.
发布者(Publisher)随着时间变化发送一系列的值给一个或者多个订阅者(Subscriber)。
一个发布者可以发布一个value,Value的类型为Output,有两种状态:成功/失败。成功会发送Value,失败就会产生Failure,Failure的类型为Error。当然如果一个发布者永远不失败,那么失败就是Never类型。
Combine内置的Publisher有Just, Future, Deferred, Empty, Fail, Record, Published以及PassthroughSubject和CurrentValueSubject。Published实际上是用propertyWrapper封装的Publisher,它可以将任意一个变量封装成一个Publisher,并通过projectedValue(影子变量)轻松实现MVVM,本文将在后续介绍。
2.2 Subscribers
Subscriber receives values from a publisher.
订阅者(Subscriber)接收发布者发送的Value。订阅者遵循的协议如下:
订阅者接受一个Input类型的Value以及接收到事件失败的类型Failure。protocol中的三个receive方法描述了订阅三种不同的生命周期,本文会在后续2.5介绍。
Publisher发布者协议中有两个通用类型参数Output和Failure。而Subscriber订阅者接受一个Input类型的Value或者接收到事件已经发送成功或者失败。既然订阅者和发布者都有了,接下来的关键是如何连接他们,连接他们的是Subscribtion(订阅),我们将在2.5中详细介绍。
使用sink方法和assign方法将在Combine内部自动创建subcribtion连接发布者和订阅者。Publisher发布者协议中有两个通用类型参数Output和Failure,而Subscriber订阅者接收发布者产生的Output和Failure,因为发布者和订阅者是互相协作的,所以一个匹配的发布者和订阅者会有Output==Input和Failure == Failure,如果不匹配,编译器会自动报错提示我们。
Combine内置了两种Subscribers,分别是Subscribers.Sink和Subscriber.Assign。简单举例说明:
注释1中我们创建了List,并使用内置的Publishers.Sequence<[Int], Never>创建了Publisher,其中Int是输入参数Output,明显是数组中的单个元素,并且指定了失败类型为Never。然后我们创了subscriber,指定input为Int,Failure为Never。然后通过subscriber方法连接他们,subcriber方法会在内部创建subcription连接Publisher和Subscriber。最终输出如下:
receiveValue:1 receiveValue:2 receiveValue:3 receiveValue:4 receiveValue:5 receiveValue:6 finished
得益于Swift的Extension,我们可以将上述创建的subscriber包裹到Publisher的Extension中,所以就有了注释2的简化版。进一步,我们可以拓展序列的Extension,将publisher封装到Sequence的扩展中,所以才有最终简化版方法注释3。
2.3 Subject
Subject主题是一种