文章目录

  • 一、 Rx 介绍
    • 1、什么是Rx
    • 2、RxSwift
    • 3、RxCocoa
  • 二、Rx 常见用法
    • 1、给 button 添加点击事件(RxCocoa)
    • 2、事件 + bind + combine
    • 3、遵循代理并实现
    • 4、闭包回调
    • 5、通知
    • 6、多任务依赖关系管理
    • 7、多任务异步并行
  • 三、DisposeBag(清除包)介绍:
  • 四、函数式编程介绍
  • 参考文献:

一、 Rx 介绍

1、什么是Rx

Rx 是 ReactiveX 的缩写,简单来说就是基于异步 Event 序列的响应式编程。Rx 可以简化异步编程方法,并提供更优雅的数据绑定,让我们可以时刻响应新的数据的同时,顺序地处理他们。

2、RxSwift

在编程过程中,我们经常需要去检测某些值的变化(如:textfield 输入变化),然后进行相应的处理。RxSwift 的出现,让程序里的时间传递响应方法做到了统一,将之前常用的事件传递方法(ru delegate、notification、target-action等),全部替换成 Rx 的“信号链”方式。

在 MVVM 的开发模式下,可以通过 RxSwift 获得更加方便的数据绑定方法,让 MVVM 更加灵活轻便。

3、RxCocoa

RxCocoa 是 RxSwift 的一部分,主要是 UI 相关的 Rx 封装。RxCocoa 实现了很多组件的绑定,协助开发者把值和控件进行绑定,避免代码中产生大量的通知、代理、数据修改等代码。也可以监听 delegate,无需把控件创建和 delegate 处理分开。

二、Rx 常见用法

1、给 button 添加点击事件(RxCocoa)

在之前,当我们需要给button添加一个点击事件的时候,得这么干:

button.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside)@objc func buttonClicked() {...
}

在使用 RxCocoa 之后,只需这样写:

button.rx.tap.subscribe { _ in // 订阅点击事件信号print("clicked button")}.disposed(by: disposeBag) // // RxSwift tap 源码
extension Reactive where Base: UIButton {/// Reactive wrapper for `TouchUpInside` control event.public var tap: ControlEvent<Void> {return controlEvent(.touchUpInside)}
}

2、事件 + bind + combine

  • share(replay: 1):共享同一个源,不单独创建新的源,以减少不必要的开支;
  • orEmpty:将可选值的 nil  转化为空字符串输出,以减少可选类型隐式解包;
  • bind:用来将一个信号发送者和一个信号监听者绑定在一起,即有信号发送,监听者自动收到通知;
  • combine:信号融合
func rxCombine() {let accountValid = accountTextField.rx.text.orEmpty.map {$0.count >= 5}.share(replay: 1)// 用 accountValid 来控制用户名提示语是否隐藏以及密码输入框是否可用。shareReplay 就是让他们共享这一个源,而不是为他们单独创建新的源。这样可以减少不必要的开支。let passwordValid = passwordTextField.rx.text.orEmpty.map {$0.count >= 5}.share(replay: 1)let everythingValid = Observable.combineLatest(accountValid, passwordValid) {$0 && $1}.share(replay: 1)accountValid.bind(to: passwordTextField.rx.isEnabled).disposed(by: disposeBag)everythingValid.bind(onNext: { [weak self] enable inif enable {self?.loginButton.isEnabled = trueself?.loginButton.setTitle("can click", for: .normal)} else {self?.loginButton.isEnabled = falseself?.loginButton.setTitle("can not click", for: .normal)}})
//    .bind(to: loginButton.rx.isEnabled).disposed(by: disposeBag)loginButton.rx.tap.subscribe { _ inprint("click the login button")}.disposed(by: disposeBag)
}

3、遵循代理并实现

传统代理方法实现:

class ViewController: UIViewController {...override func viewDidLoad() {super.viewDidLoad()scrollView.delegate = self}}extension ViewController: UIScrollViewDelegate {func scrollViewDidScroll(_ scrollView: UIScrollView) {print("contentOffset: \(scrollView.contentOffset)")}}

使用 Rx 实现:

class ViewController: UIViewController {...override func viewDidLoad() {super.viewDidLoad()scrollView.rx.contentOffset.subscribe(onNext: { contentOffset inprint("contentOffset: \(contentOffset)")}).disposed(by: disposeBag) // 每一个绑定是有生命周期的,并且这个绑定是可以被清除的。将每一个绑定的生命周期交给 disposeBag 管理,当 disposeBag 释放时,会自动清理 _disposables 数组中所有的绑定}
}

4、闭包回调

传统实现方案:

URLSession.shared.dataTask(with: URLRequest(url: url)) { (data, response, error) inguard error == nil else {print("Data Task Error: \(error!)")return}guard let data = data else {print("Data Task Error: unknown")return}print("Data Task Success with count: \(data.count)")
}.resume()

Rx 实现方案:

URLSession.shared.rx.data(request: URLRequest(url: url)).subscribe(onNext: { data inprint("Data Task Success with count: \(data.count)")}, onError: { error inprint("Data Task Error: \(error)")}).disposed(by: disposeBag)

通过 Rx 的方式,让回调变得非常的简单。

5、通知

var notificationObserver: NSObjectProtocol!override func viewDidLoad() {super.viewDidLoad()notificationObserver = NotificationCenter.default.addObserver(forName: .UIApplicationWillEnterForeground, object: nil, queue: nil) { (notification) inprint("Application Will Enter Foreground")}
}deinit {NotificationCenter.default.removeObserver(notificationObserver)
}

Rx 实现方式:

override func viewDidLoad() {super.viewDidLoad()NotificationCenter.default.rx.notification(.UIApplicationWillEnterForeground).subscribe(onNext: { (notification) inprint("Application Will Enter Foreground")}).disposed(by: disposeBag)
}

6、多任务依赖关系管理

多任务依赖管理管理,如异步串行请求,由于业务原因,可能会存在请求依赖的场景,如:登录完成获取到token后才能请求用户信息。

func login(userName: String, password: String, completion: @escaping (_ result: Result<Any, Error>?) -> Void) {DispatchQueue.global().async {print("normal login success")completion(nil)}
}func loadUserInfo(completion: @escaping (_ result: Result<Any, Error>?) -> Void) {DispatchQueue.global().async {print("normal load user info success")completion(nil)}
}func loadRecommendsGoods(completion: @escaping (_ result: Result<Any, Error>?) -> Void) {DispatchQueue.global().async {print("normal load recommend goods success")completion(nil)}
}// 嵌套调用,异步串行
func normal_taskStart() {login(userName: "enoch", password: "11111") { [weak self] _ inself?.loadUserInfo { [unowned self] _ inself?.loadRecommendsGoods { _ in// do nothing}}}
}

Rx 实现方式

func rx_login(userName: String, password: String) -> Observable<String> {let createSequence =  Observable<String>.create { observer -> Disposable inDispatchQueue.global().async {print("rx login success")observer.onNext("login success")observer.onCompleted()}return Disposables.create()}return createSequence
}func rx_loadUserInfo() -> Observable<[String : Any]> {let createSequence = Observable<[String : Any]>.create { observer -> Disposable inDispatchQueue.global().async {print("rx load user info success")observer.onNext(["name" : "enoch", "age" : 18])observer.onCompleted()}return Disposables.create()}return createSequence
}func rx_loadRecommendsGoods() -> Observable<[String]> {let createSequence = Observable<[String]>.create { observer -> Disposable inDispatchQueue.global().async {print("rx load recommend goods success")observer.onNext(["goods1", "goods2", "goods3"])observer.onCompleted()}return Disposables.create()}return createSequence
}// 异步串行调用
func rx_taskStart() {rx_login(userName: "enoch", password: "111111").flatMap { [unowned self] _ in self.rx_loadUserInfo() }.flatMap { [unowned self] _ in self.rx_loadRecommendsGoods() }.subscribe(onNext: { goodsArray inprint(goodsArray)}).disposed(by: disposeBag)
}

7、多任务异步并行

Rx 当中,可使用压缩信号的方式,进行多任务异步并行,示例代码如下:

func rx_zipTask() {Observable.zip(rx_login(userName: "enoch", password: "111111"),rx_loadUserInfo(),rx_loadRecommendsGoods()).subscribe(onNext: { (token, userData, goodsData) inprint("token:\(token)")print("user data:\(userData)")print("goods data:\(goodsData)")}, onError: { error in// do nothing}).disposed(by: disposeBag)
}

三、DisposeBag(清除包)介绍:

  • DisposeBag 有一个专门存放垃圾回收的 _disposables 数组;和一个表示当前对象是否被回收的属性值_isDisposed (默认是false);
  • 当 DisposeBag 的生命周期在 Viewcontroller 中结束的时候,调用自身的 deinit,随后调用 self.dispose();
  • 紧接着 会将_isDisposed 变成ture,然后循环遍历 _disposables 数组,并将所有 Disposable对象都调用 dispose() 方法进行释放
  • 每一个绑定是有生命周期的,并且这个绑定是可以被清除的。将每一个绑定的生命周期交给 disposeBag 管理,当 disposeBag 释放时,会自动清理 _disposables 数组中所有的绑定

四、函数式编程介绍

编程范式了解一下:

  • 命令式:命令式编程通过一系列改变程序状态的指令来完成计算。命令式编程模拟电脑运算,是行动导向的,关键在于定义解法,即“怎么做”,因而算法是显性而目标是隐性的;
  • 声明式:声明式编程只描述程序应该完成的任务。声明式编程模拟人脑思维,是目标驱动的,关键在于描述问题,即“做什么”,因而目标是显性而算法是隐性的;

函数式编程是指声明式范式编程,它需要我们将函数作为参数传递,或者作为返回值返还,我们可以通过组合不同的函数来得到想要的结果。

函数式编程优势:

  • 减轻程序猿思考的负担,降低出错可能性,简称防秃;
  • 代码可读性高;
  • 代码更简洁;
  • 适用于并发环境;
  • 易于优化;
  • 细粒度的重用(函数级别);
  • 易于测试;

下方是简单举例:

func studentFilter() {let studentsInGradeThreeClassThree = allStudents().filter { student -> Bool in student.grade == 3 && student.cls == 3 }print("三年级三班有 \(studentsInGradeThreeClassThree.count) 人")studentsInGradeThreeClassThree.filter { student -> Bool in student.sex == .male }.forEach { boy in boy.singASong() }studentsInGradeThreeClassThree.filter { student -> Bool in student.score > UInt(90) }.forEach { student in print(student.father) }studentsInGradeThreeClassThree.sorted { (student1, student2) -> Bool in student1.score > student2.score }.forEach { student in print("\(student.name): \(student.score)") }}

参考文献:

1、swift 官方中文文档

RxSwift 介绍与简单使用相关推荐

  1. Matplotlib的介绍及简单操作

    Matplotlib的介绍及简单操作 1 什么是Matplotlib 是专门用于开发2D图表(包括3D图表) 以渐进.交互式方式实现数据可视化 2 为什么要学习Matplotlib 可视化是在整个数据 ...

  2. (三)AJAX基本介绍和简单实例03

    (三)AJAX基本介绍和简单实例03-----Ajax与数据库的动态应用 前台显示界面: 选择所有客户之后: 选择其中一个客户---杜森: Demo03.html代码 <html> < ...

  3. rabbitMQ消息队列 – 面板介绍及简单demo

    首先rabbit安装好之后,运维会给一个控制面板. 默认账号密码为guest 登入以后可以看到具体界面. 在此鸣谢百度翻译给予的大力支持.. ###写一个简单的demo 编写之前..虽然说可以直接用底 ...

  4. Protobuf介绍及简单使用(上)

    目录 Protobuf 介绍 优势 protobuf语法 Specifying Field Rules Data type Data name Number Protobuf注释 保留字段与标识符 s ...

  5. SQL Server中追踪器Trace的介绍和简单使用

    原文:SQL Server中追踪器Trace的介绍和简单使用 一.What is Trace? 对于SQL Profiler这个工具相信大家都不是很陌生,没用过的朋友可以在SQL Server Man ...

  6. S3C2440移植linux3.4.2内核之内核框架介绍及简单修改

    文章目录 uboot启动内核分析 简单配置内核 编译内核 设置机器ID 修改晶振 移植Linux3.4.2内核其他文章链接: S3C2440移植linux3.4.2内核之内核框架介绍及简单修改 S3C ...

  7. 新颖的自我介绍_简单新颖的自我介绍范文

    简单新颖的自我介绍范文 简单新颖的自我介绍范文1 各位考官好,今天能够站在这里参加面试,有机会向各位考官请教和学习,我感到非常的荣幸.希望通过这次面试能够把自己展示给大家,希望大家记住我.我叫.... ...

  8. Quartz框架实现定时任务介绍及简单使用

    https://blog.csdn.net/bicheng4769/article/details/81097305 Quartz框架介绍及简单使用 https://www.cnblogs.com/d ...

  9. Hive第一天——Hive介绍以及简单使用

    Hive第二天--Hive介绍以及简单使用 自己的话:黑发不知勤学早,白首方悔读书迟 每天都要保持前进! 一.什么是Hive 数据库: mysql.oracle.sqlserver.DB2.sqlit ...

  10. Helm模板常用语法介绍与简单应用场景

    Helm模板常用语法介绍与简单应用场景 文章目录 Helm模板常用语法介绍与简单应用场景 什么是Helm _help.tpl子模版 应用场景 预定义对象 关于变量 关键字及应用 函数 流程与控制 什么 ...

最新文章

  1. 巧妙共享Win7/Vista/XP文件夹权限
  2. C语言--static修饰函数
  3. 17.C#类型判断和重载决策(九章9.4)
  4. 从EMD、WMD到WRD:文本向量序列的相似度计算
  5. kafka to mysql_Flink : kafka to mysql example
  6. android系统相机自动录像,android 调用系统相机录像并保存
  7. 【汇总】numpy函数合集
  8. c++向量和数组的区别_Matlab入门基础知识(5)对数组的操作
  9. IDEA中Maven项目中界面右边的Maven Projects窗口找不到不出来
  10. eclipse打war包_jar包和war包的区别
  11. 阿里影业“云智开放平台”炼成记!
  12. sentinel 打包_SpringCloud Alibaba整合Sentinel
  13. 配置apache密码认证
  14. 5-9 第五天 微信 JS-SDK-使用微信官方的WEB调试工具
  15. 三段式状态机原理详细解释
  16. python自然语言处理 | 分析句子结构
  17. cannot load facet kotlin
  18. Spectral Clustering(谱聚类和其他)
  19. Facebook MySQL工程师吐槽MemSQL:MySQL比你们快无数倍
  20. 课程设计:经验以及答辩情况汇总

热门文章

  1. Lecture06:市场出清问题的鲁棒方法
  2. [分析力学]解题思路 - 拉格朗日方程
  3. 运筹学-2-单纯形法的矩阵计算
  4. 1553B总线通信协议
  5. UOJ 180【UR #12】实验室外的攻防战
  6. hht时频谱 matlab 乱序_用HHT求取信号的时频谱与边际谱——转
  7. 月下夜想曲200.6(攻略2)
  8. Android实现网络视频播放
  9. Entry name ‘res/drawable-xhdpi-v4/ic_launcher.png‘ collided
  10. 怎么让照片变年轻_PS高手让你变得更年轻