写点什么

【技研录】响应式编程在 Swift 中的使用

  • 2023-11-24
    北京
  • 本文字数:3225 字

    阅读完需:约 11 分钟

【技研录】响应式编程在 Swift 中的使用

写作思考:

响应式编程(Reactive Programming)是一种编程范式,它以数据流和变化传递为核心概念,可以简化代码结构,提高程序的可读性和可维护性。在 Swift 中,响应式编程已经得到了广泛的应用,并成为了一些流行框架的基础,开发者可以通过框架提供的操作符对数据流进行各种变换。目前在众安科技经代 App 中全面使用,整体代码逻辑更加清晰,开发效率上得到了明显的提升。


目录

1.什么是响应式编程

2.函数式 Swift

3.MVVM

4.MVVM 与响应式结合

5.总结


一.什么是响应式编程

 

Wiki 上的解释: Reactive programming 是一种面向数据串流和变化传播的声明式编程范式。

iOS 客户端的原生开发使用 Objective-C 和 Swift 开发,使用 Objective-C 的时候注重面向对象编程,大多数都是使用命令式的编程,Swift 更注重面向协议编程、函数式编程。

 

做过 iOS 客户端的同学一定了解过 KVO 这个内置的 Api,KVO 可以帮助我们将属性的变更和变更后的处理分开,简单的理解就是一个对象的属性改变后,另外一连串对象的属性都随之发生改变。KVO 的写法和使用上比较复杂,而且只支持 NSObject ,局限性太大。 

 

Apple 在推出 Swift 之后,响应式的编程基于数据流的理念,异步的处理事件和函数式编程能很好的结合,ReactiveX 推出了响应式的库 RxSwift,WWDC 2019 上 Apple 公布了声明式全新界面框架 SwiftUI,以及配套的响应式编程框架 Combine,Combine 只支持 iOS13 以上的系统,毕竟属于原生的框架,在性能上要稍微强于 RxSwift,根据支持的版本差异开发者可以自行选择。 

 

最新推出 Rx 的微软对响应式编程的解释是 Rx = Observables + LINQ + Schedulers,通俗一些的解释就是面向异步数据流编程。数据流可以有多种形式,比如读取一个文件、进行一个网络请求、用户出发的行为等等,都可以认为是一种数据流,当然一个变量也可以认为是一种数据流。

                                   

二.函数式 Swift

 

函数式编程中的函数这个词不是指计算机中的函数,而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如 sqrt(x) 函数计算 x 的平方根,只要 x 不变,不论什么时候调用,调用几次,值都是不变的。


1. 一等公民函数与高阶函数


在函数式编程中,函数是一等公民,不再把函数想象成一个处理过程,而是把它当作一个对象或者变量来对待。

 

 

在 Swift 中可以很方便的把一个函数赋值给一个常量,这个在 Objective-C 中是做不到的。所谓的高阶函数,指可以将其他函数作为参数或者返回结果的函数,Swift 中的函数都是高阶函数,系统库提供了(map,fillter,reduce 等)

 


通过函数这个“管道”,数据从一头经过“管道”到另一头,就得到了想要的数据。

 

2.柯里化

 

Swift 里可以将方法进行柯里化 (Currying),这是也就是把接受多个参数的方法进行一些变形,使其更加灵活的方法。函数式的编程思想贯穿于 Swift 中,而函数的柯里化正是这门语言函数式特点的重要表现。

 


柯里化是一种量产相似方法的好办法,可以通过柯里化一个方法模板来避免写出很多重复代码,也方便了今后维护。

 

3.闭包

 

闭包是一个会对它内部引用的所有变量进行隐式绑定的函数。也可以说,闭包是由函数和与其相关的引用环境组合而成的实体。函数实际上是一种特殊的闭包,你可以使用{ }来创建一个匿名闭包。使用 in 来分割参数和返回类型。

 


上面 map 函数遍历了数组,用闭包处理了所有元素,并返回了一个处理过的新数组。

那么遵循以上特性,一个好的 Swift 函数式程序会具有一下特质:

 

  ● 模块化:相较于把程序认为是一系列赋值和方法调用,函数式开发者更倾向于强调每个程序都能够被反复分解为越来越小的模块单元,而所有这些块可以通过函数装配起来,以定义一个完整的程序。

 

  ● 对可变状态的谨慎处理:面向对象编程专注于类和对象的设计,每个类和对象都有它们自己的封装状态。然而,函数式编程强调基于值编程的重要性,这能使我们免受可变状态或其他一些副作用的困扰。通过避免可变状态,函数式程序比其对应的命令式或者面向对象的程序更容易组合。

 

  ● 类型:一个设计良好的函数式程序在使用类型时应该相当谨慎。精心选择你的数据和函数的类型,将会有助于构建你的代码,这比其他东西都重要。Swift 有一个强大的类型系统,使用得当的话,它能够让你的代码更加安全和健壮。

 

在实际开发过程中,我们遵循函数式思维去编码,可以很容易地使用 Swift 写出函数式风格的代码,为我们带来以下好处:

 

1. 方便组件解耦

2. 单元测试和调试都更容易

3. 更方便的代码管理

 

三.MVVM

 

MVVM 可以说几乎就是一个 MVC,不过通过 View Model 层来将数据和视图进行绑定。熟悉 iOS 开发的小伙伴都知道,iOS 的 Cocoa 框架都是基于 MVC 设计的,关于 MVC,我们可以看下斯坦福的 CS193p Paul 这张经典图



MVC 本身的概念相当简单,同时它也给了开发者很大的自由度。Massive View Controller 往往就是利用了这个自由度,“随意”地将逻辑放在 Controller 层所造成的后果,此时的 M 不是 Model 已经变成了 Massive。



使用 MVVM 之后可以大大减轻 View Controller 职责,简化后的各个模块分工更加明确,更加方便集成和开发。我们在使用的时候主要遵循一下几个事项:

    ●  ViewController 尽量不涉及业务逻辑,让 ViewModel 去做这些事情,此时的 ViewModel 实际上的职责是 Controller

    ● ViewModel 绝对不能包含视图 View(UIKit.h),不然就跟 View 产生了耦合,不方便复用和测试

    ● iewModel 避免过于臃肿,否则重蹈 Controller 的覆辙,变得难以维护

 

MVVM 是 MVC 的升级版,完全兼容当前的 MVC 架构,MVVM 虽然促进了 UI 代码与业务逻辑的分离,一定程度上减轻了 ViewController 的臃肿度,但是 View 和 ViewModel 之间的数据绑定使得 MVVM 变得复杂和难用了,如果我们不能更好的驾驭两者之间的数据绑定,同样会造成 Controller 代码过于复杂,代码逻辑不易维护的问题。


四.MVVM 与响应式结合

 

上面介绍完 MVVM,那应该怎么和响应式结合起来呢?我们先来看下在 iOS 中是怎么进行状态更新的

  ● Target-Action

  ● Delegate

  ● KVO

  ● Notifications

  ● Callback

 

多种回调方式,适用规则、适用场景都不相同,这增加了开发、维护的难度。如果有一种方式可以把状态更新做到统一,那就可以大大提高开发效率,这里就要提到 Rx 了,它把状态变更都转化成流,MVVM 中的 ViewModel 和 Rx 相结合这样就可以做到响应式了。

 

先来看个例子,一个登录界面



产品经理说了需求:

  ● 账号是手机号 11 位

  ● 密码大于 6 位

  ● 当满足上面条件,点击统一条款,下面登录按钮为可点击状态否则不可点击

 

按照一般思路,2 个输入框对应的是 2 个 UITextField 控件,还有 2 个 UIButton 控件对应单选按钮和登录按钮,我们需要实现这个需求就要做到以下:

  1. 在 UITextField 的 Delegate 里面去监听输入的内容

  2. 在 UIButton 的 Action 方法里面监听隐私条款是否点击

  3. 2 个输入框和 1 个隐私按钮,这 3 个控件每次更新状态都要去看另外 2 个是否满足登录按钮可点击

 

可以见到这样一个简单的需求,在代码实现上要处理的逻辑很多,而且都是分散的,那么我们能不能只罗列条件,然后把这些条件扔给一个条件处理的机制,这个机制就能帮我们正确的处理这些关系?

 

 

伪代码如下:


 

实际处理中会把这些逻辑放到 ViewModel,这样就把 RxSwift,函数式,MVVM 结合起来,达到了响应式编程的样子。

 

五.总结

 

Swift 从 2014 年发布,到 iOS13 推出的响应式 Combine,开源也一直推动语言的发展,可能未来 1 天苹果会抛弃原来 Cocoa 框架实现,利用新语言的特性也不是不可能。任何架构和技术都不能满足所有的工程需求,能够使用简单的架构来搭建复杂的工程,制作出让其他开发者可以轻松理解的软件,避免高额的后续维护成本,让软件可持续发展并长期活跃,应该是每个开发者在构建软件是必须考虑的事情。

 

参考资料:

 

  1. 关于 MVC 的一个常见的误用

  2. iOS 下的响应式编程

公众号推荐:

AGI 概念引发热议。那么 AGI 究竟是什么?技术架构来看又包括哪些?AI Agent 如何助力人工智能走向 AGI 时代?现阶段营销、金融、教育、零售、企服等行业场景下,AGI应用程度如何?有哪些典型应用案例了吗?以上问题的回答尽在《中国AGI市场发展研究报告 2024》,欢迎大家扫码关注「AI前线」公众号,回复「AGI」领取。

2023-11-24 16:59696

评论

发布
暂无评论
发现更多内容

Vue.js项目无法启动:sh: 1: vue-cli-service: not found

codists

vue.js

springboot启动流程之createApplicationContext

梦倚栏杆

【Flutter 专题】108 图解 PageView 滑动页面预览小尝试

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 6月日更

聊聊Go的包管理

架构精进之路

包管理工具 Go 语言 6月日更

分布式系统中的ID是如何生成的

卢卡多多

电商 分布式ID 6月日更 签约计划第二季

浪潮云说丨数据工场助力行业数据发挥生产要素新价值

浪潮云

云计算

week6 作业

Geek_2e7dd7

架构实战营

Java 并发编程—— ThreadPoolExecutor 分析应用

Antway

6月日更

情感分析 | AI没有“心”,却能“读心”

澳鹏Appen

人工智能 自然语言处理 机器学习 nlp 训练数据

如何用Python快速的搜索邮件

IT蜗壳-Tango

6月日更

【21-2】什么是 PowerShell

耳东@Erdong

windows PowerShell 6月日更

手撸Spring框架,设计与实现资源加载器,从Spring.xml解析和注册Bean对象

小傅哥

spring 小傅哥 资源加载器 解析xml 注册Bean对象

中文技术文章排版

KooFE

6月日更

一文回顾 Java 入门知识(下)

逆锋起笔

Java 面向对象 JAVA开发 java基础 javase

教你在Kubernetes中快速部署ES集群

华为云开发者联盟

Kubernetes 监控 中间件 集群 ES集群

CloudQuery 的数据安全技术运用

BinTools图尔兹

Java 数据库 sql 数据安全

高性能JavaScriptの结语 -- 学完了

空城机

JavaScript 6月日更

【Vue2.x 源码学习】第九篇 - 对象数据变化的观测情况

Brave

源码 vue2 6月日更

ONES CTO 冯斌 | 项目管理是软件研发的刚需

万事ONES

项目管理 研发管理 ONES

想听世界上最懂 JavaScript 的人和你讲JavaScript 吗?

博文视点Broadview

深圳站 | 鹏城再聚,赋能未来,金沙古酒百城巡展第39站完美收官!

科技热闻

融合创新与头雁领路:通过北京人工智能产业联盟能读懂什么?

脑极体

Scrum为何倡导固定迭代周期?

万事ONES

项目管理 Scrum 敏捷开发 Agile ONES

工厂管理没有头绪?那是你还没有可视化操控设备

一只数据鲸鱼

数据可视化 工业互联网 工业4.0 智慧工厂

【LeetCode】零钱兑换 IIJava题解

Albert

算法 LeetCode 6月日更

小程序电商系统微服务拆分

唐高为

Packer 自动化镜像构建

HoneyMoose

读深入ES6记[三]

蛋先生DX

ES6 6月日更

vue3真香Api——Reactivity

法医

大前端 Vue 3 6月日更

ONES CTO 冯斌 | 高效研发团队的技术管理之道

万事ONES

管理 研发管理 技术管理 ONES

动态规划最长公共子序列(LCS)问题(Java实现)

若尘

动态规划 java编程 6月日更

【技研录】响应式编程在 Swift 中的使用_云计算_众安保险_InfoQ精选文章