75142913在线留言
【Combine入门】初识Combine框架_IOS开发_网络人

【Combine入门】初识Combine框架

Kwok 发表于:2021-12-14 20:14:19 点击:5 评论: 1

当我们使用SwiftUI进行MVVM模式开发的后期,将越来越依赖使用Combine框架,苹果公司对于Combine是这样描述的:

Combine框架提供了一个声明性的Swift API,用于随着时间的推移处理值。这些值可以表示多种异步事件。组合声明发布者以公开可以随时间变化的值,并结合订阅者从发布者那里接收这些值。 

这样的描述很官方,读很多次依然不知道Combine框架是做什么的,其实我们可以通俗的理解为对输入、输出数据流的处理(个人理解为:流水线模式数据处理)。本文将对Combine框架的使用场景,理论基础进行一个简单的介绍。

Combine框架使用一种叫函数响应式的编程方式,“函数响应式编程(Functional reactive programming)”简写为FRP。其处理流程为:收到网络请求 -> 映射到JSON模式 -> 发布映射成功的数据 -> 数据变化导致View重建(UI显示接收到的数据)

而Combine框架我们需要关注3个重点:发布者 Publisher和特殊发布者Subjects -> Operator操作者(介于发布者与订阅者之间)  ->  Subscriber订阅者,了解Combine的流程与概念后我们只需要重点学习Operator的相关处理函数即可。

Combine入门初识Combine框架

一、通过一个简单的示例了解Combine框架

下面我们将使用Combine框架完成了一个点击开始计数的代码示例(为了方便拷贝代码,我将ViewModel与View放到了一个文件里):

import SwiftUI
import Combine //导入Combine框架

//ViewMode 视频模型
class TimerCount:ObservableObject{
    @Published var counter = 0 //发布对象
    var subscription:AnyCancellable? //定义一个可取消的订阅者 Subscriber 
    func startTimer(){
        print("计数开始")
        //subscription 订阅 Timer的发布
        subscription = Timer //Foundation 自带的时间发布者
            //every发布频率:每0.1秒,ON在:主线程,in:模式:一种包含一个或多个其他运行循环模式的伪模式。
            .publish(every: 0.1, on: .main, in: .common)
            //-------------下面是操作者Operator--------------------//
            .autoconnect()//自动连接到上游可连接发布程序的发布程序。
            .scan(0, { count,_ in
                return count + 1 //通过向闭包提供当前元素以及该闭包返回的最后一个值,从上游发布器转换元素。
            })
            .sink(receiveCompletion: { _ in
                print("发布完成")
            }, receiveValue: { count in
                print("同步更新UI数据")
                self.counter = count
            })
    }
    
    func stopTimer(){
        print("停止计数")
        subscription?.cancel()//取消订阅
    }
        //返回一个随机的颜色
    func randomPlaceholderColor() -> Color{
        [.red,.black,.orange,.mint,.purple,.yellow,.gray,.green,.black,.brown,.pink,.primary].randomElement()!
    }
}
//View 视图
struct TimerCountView: View {
    @StateObject var timer = TimerCount()//订阅者
    var body: some View {
        VStack(spacing:35){
            Text("\(timer.counter)")
                .font(.largeTitle)
                .fontWeight(.bold)
                .foregroundColor(timer.randomPlaceholderColor())//随机颜色
            
            HStack{
                myButton("开始计数"){ timer.startTimer() }
                myButton("停止计数"){ timer.stopTimer() }
            }
        }
    }
    func myButton(_ text:String, action: @escaping () -> Void) -> some View{
        Button(action: action){ Text(text) }
        .buttonStyle(.borderedProminent)
    }
}

在这篇文章里有对 发布者、订阅者进行一个简单的说明:http://www.neter8.com/ios/159.html

通过上面的演示代码我们可以看到,subscription 是一个订阅者,通过 “ subscription = Timer ”开始对发布者“Timer”发出订阅请求,然后通过后续的 .publish 、.autoconnect 、.scan 等操作者对数据处理后,由.sink 完成订阅,这就是官方文档所说的”时间的推移“从上到下分步处理后交给下一级继续处理。我们这里重点理解每个操作者函数的使用方式和合适的使用时间、位置,就基本就算得上Combine入门了。

上面的代码简单理解为:创建一个每0.1秒发布一次的”逻辑规则“,通过.scan来观察1个或者多个元素的变化、处理(可能会失败的)异步操作、随时间改变流的内容。处理事件流、时间、错误的发生,并协调系统如何去响应一个事件,这就是是函数响应式编程的核心。

二、Combine概念

要学习Combine我个人觉得应该从正确的将这个单词翻译成恰当的中文,通常我们使用翻译软件翻译成“组合”,我觉得将其翻译成“数据组装器”更为合适,因为从: 发布者(Publisher) -> 操作者(Operators) -> 订阅者(Subscriber) 数据流向过程可以看出来,这就像工厂的流水线一样。而这条流水线将是我们要理解的“管道”。发布者将数据放到流水线上(管道),操作者负责对这些数据进行处理,如“过滤、合并、解码”等操作。最终将处理好的数据传输给订阅者。这就是整个Combine框架的核心工作。

(Combine 流水作业示意图)

从 Publisher 到 Operator 再到 Subscriber 的调用是链式的,Operator 的输入是 Publisher,输出仍然是 Publisher,得益于 Operator 的高度解耦,我们可以对数据进行多次处理,并且对其的测试也是比较容易的。

publisher 和 subscriber,在 Swift 中被描述为协议。 从上面的示意图可以看到,不管是发布者、订阅者还是操作者,他们总是持有相同的2个数据,发布者的Output输出的类型与订阅者Input输入的类型是同一个数据,只是经过操作者的时候会对数据进行处理。而Failure携带的是每次数据可能会产生的错误信息。我们可以使用Never忽略掉错误。

三、SwiftUI里的:发布者(publisher)、操作者(Operators)、订阅者(subscriber)、对象 (Subjects)核心概念

在知道Combine的核心工作之后,在开发使用时需要对下面的几个核心概念进行深入的理解。这也是数据流向及处理的核心。

我们根据上面的Combine 流水作业示意图顺序,逐步介绍每个阶段的数据处理函数。

1、Publisher(发布者)

发布者提供一个可获取(网络抓取、读取本地文件等)、可生成(自定义内容)的数据,也是将数据放到流水线(管道)上让操作者处理的源头,如上面的代码中我们通过Foundation框架的Timer发布一个定时器(自定义生成的内容)。如果发布者没有被订阅(“ subscription = Timer ”),则Timer不会发布任何的数据。

当我们使用.scan对发布数据处理时,会用两种 相关的类型(associatedtype)来描述:Output(发布的对象)、Failure(发布失败),比如上面代码里我们发布的对象是一个Int值,使用”_“忽略了失败结果。

发布者如果返回 String类型的数据 ,并且可能返回的错误类型是URLError,那么发布者可以用 <String, URLError> 来描述。

最新的发布者请参考官方文档:https://developer.apple.com/documentation/combine/publisher

发布者是Combine的重要核心功能之一,提供了若干且官方会不断更新其提供的发布者函数,我们需要深刻学习发布者提供的功能,所以我使用单独的文章对发布者的功能整理,请稳步下面的地址:

发布者详细介绍与说明:http://www.neter8.com/ios/184.html

2、Operators(操作者)

操作者是苹果参考文档中包含的一些预构建功能的便捷名称。 操作者用来组合成管道(流水线上处理各部份的工厂)。 许多操作者会接受开发人员的一个或多个闭包,以定义业务逻辑,同时保持并持有发布者/订阅者的生命周期(让流水线正常运行)。

一些操作者支持合并来自不同管道的输出(多条流水线上的数据合并)、更改数据的时序或过滤所提供的数据。 操作者可能还会对操作类型有限制(不符合的数据抛弃、替换、修改等), 还可用于定义错误处理和重试逻辑、缓冲和预先载入以及支持调试。

所以操作者是一个既像订阅者又像发布者的对象。操作者是同时实现了订阅者协议发布者协议。 它们支持订阅发布者,并将结果发送给任何订阅者。 

最新的操作者请参考官方文档:https://developer.apple.com/documentation/combine/future-publisher-operators

操作者详细介绍与说明:http://www.neter8.com/ios/185.html

3、 Subscriber(订阅者)

 相比发布者,订阅者学习起来比较容易,Combine 里有两个内建的订阅者: Assign 和 Sink。 而我们使用的SwiftUI 中有一个订阅者: onReceive。所以,只要掌握了这3个功能就基本能就应复开发中的大部份问题。

订阅者支持取消操作,取消时将终止订阅关系以及所有流完成之前,由发布者发送的数据。 Assign 和 Sink 都遵循 Cancellable 协议.

最后的订阅者请参考官方文档:https://developer.apple.com/documentation/combine/subscriber

订阅者详细介绍与说明:http://www.neter8.com/ios/186.html

4、Subjects (对象) 

 Subjects 是一种遵循 Subject 协议的特殊的发布者。 这个协议要求 subjects 有一个 .send(_:) 方法,来允许开发者发送特定的值给订阅者或管道。

Subjects 可以通过调用 .send(_:) 方法来将值“注入”到流中, 这对于将现有的命令式的代码与 Combine 集成非常有用。

一个 subject 还可以向多个订阅者广播消息。 如果多个订阅者连接到一个 subject,它将在调用 send(_:) 时向多个订阅者发送值。 一个 subject 还经常用于连接或串联多个管道,特别是同时给多个管道发送值时。

四、Cmbine 热门功能

每年框架都会更新,本文也没有办法及时的列出来所有的发布者相关的函数,下图是WWDC列出的最常用的热门函数单词。

Combine入门初识Combine框架

上面图片中列出了Combine框架里使用频率比较高的相关功能,如果都掌握了,基本上可以随心所欲的使用Combine。

除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:http://www.neter8.com/ios/183.html
标签:Combine框架Kwok最后编辑于:2021-12-20 20:20:07
0
感谢打赏!

《【Combine入门】初识Combine框架》的网友评论(1)

  1. #1Combine是未来IOS开发必须学习的路径,对于我们学习与进步有很大的帮忙,配置SwiftUI框架,简直是完美组合。
    admin于1周前(2021-12-27)发表。(0)(0)

本站推荐阅读

热门点击文章