Swift知识点---RxSwift学习
1. 什么是RxSwift
RxSwift是Swift函数响应式编程的一个开源库,由Github的ReactiveX组织开发、维护
RxSwift的目的是:让数据/事件流 和 异步任务能够更方便的序列化处理,能够使用Swift进行响应式编程
RxSwift本质上还是观察者模式,并且是一个响应式的,并且可以序列化的
观察者模式
观察者模式包括:KVO、通知等
爸爸妈妈照看观察宝宝
其中,宝贝就是被观察者
爸爸妈妈就是观察者,或者说是订阅者
只要被观察者(宝宝)发出来某些事件,比如哭声、叫声,则被称为事件,通知到订阅者
此时,订阅者就可以做响应的工作
RxSwift做了什么?
RxSwift把我们程序中的每一个操作都看成一个事件
比如一个TextField中的文本改变、一个按钮被点击、一个网络请求结束等
每一个事件源就可以看成一个管道,也就是sequence
比如,TextField,当我们改变里面的文本的时候,这个TextField就会不断的发出事件
从他的sequence中不断流出,我们只需要监听这个sequence,每流出一个事件就做相应的处理
同理,Button也是一个sequence,每点击一次就流出一个事件
理解Observable和Observer

2. RxSwift简单体验
- RxSwift监听按钮的点击
- RxSwift监听UITextField的文字改变
- RxSwift改变Label中的文字
- RxSwift监听对象属性改变
- RxSwift监听UIScrollView的滚动
- …
//导入RxSwift
import RxSwift
import RxCocoa
按钮监听
原始方法:
button.addTarget(self, action: #selector(button1Click), for: .touchUpInside)
使用RxSwift的方法:
self.button.rx.tap.subscribe { (event: Event<Void>) inprint(event)
}
上述方法会有一个标黄的警告:Result of call to ‘subscribe’ is unused
修改方法:private lazy var disposeBag: DisposeBag = DisposeBag()self.button.rx.tap.subscribe { (event: Event<Void>) inprint(event) }.disposed(by: disposeBag)```
监听UITextField文字的改变
方法一:传统方法
略
方法二:
self.view.addSubview(self.textField)
self.textField.frame = CGRect(x: 200, y: 300, width: 100, height: 40)
self.textField.rx.text.subscribe { (event: Event<String?>) inprint(event.element)//获取信息
}.disposed(by: disposeBag)
这种方法,获取的event有两个Optional包裹着,使用起来不方便
方法三:
self.textField.rx.text.subscribe { (myString: String?) inprint(myString)//获取的是Optional类型
} onError: { error inprint(error)
} onCompleted: {print("onCompleted")
} onDisposed: {print("onDisposed")
}.disposed(by: disposeBag)
以上可以简化:
self.textField.rx.text.subscribe { (myString: String?) inprint(myString)//获取的是Optional类型
}.disposed(by: disposeBag)
监听Label中的文字
UITextField文字输入,然后Label显示输入的文字
方法一:
self.textField.rx.text.subscribe { (myString: String?) inprint(myString)self.myTitleLabel.text = myString
}.disposed(by: disposeBag)self.view.addSubview(myTitleLabel)
myTitleLabel.frame = CGRect(x: 100, y: 210, width: 200, height: 40)
方法二:
self.textField.rx.text.bind(to: myTitleLabel.rx.text).disposed(by: disposeBag)self.view.addSubview(myTitleLabel)
myTitleLabel.frame = CGRect(x: 100, y: 210, width: 200, height: 40)
RxSwift的KVO
self.view.addSubview(myTitleLabel)
myTitleLabel.frame = CGRect(x: 100, y: 210, width: 200, height: 40)myTitleLabel.rx.observe(String.self, "text").subscribe { (str: String?) inprint(str)
}.disposed(by: disposeBag)
RxSwift监听UIScrollView的滚动
self.view.addSubview(scrollView)
scrollView.frame = CGRect(x: 100, y: 280, width: 200, height: 150)
scrollView.rx.contentOffset.subscribe { (point: CGPoint) inprint(point)
}.disposed(by: disposeBag)
3. RxSwift常见操作
Never、Empty、Just、Of、From、Create、Range、RepeatElement
- Never,什么都不执行
///never,啥事没有
let observableNever = Observable<String>.never()
observableNever.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)
- Empty创建一个空的sequence,只能发出一个completed事件
//只执行completed
let observableEmpty = Observable<String>.empty()
observableEmpty.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)打印结果:
completed
- Just是创建一个sequence,只能发出一种特定的事件,并且能正常结束
也就是,特定事件可以监听,complete事件可以监听
///Just:只执行特定类型+complete
let observableJust = Observable.just(123)//Int类型
observableJust.subscribe { (event: Event<Int>) in//Event<Int>相对应print(event)
}.disposed(by: disposeBag)打印结果:
next(123)
completed
- Of可以执行特定类型+complete
- 创建一个sequence,可以发出多个事件信号
///Of: 可以执行特定类型多个事件+complete
let observableOf = Observable.of("1", "2", "3", "6")
observableOf.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)打印结果:
next(1)
next(2)
next(3)
next(6)
completed
- From从数组中创建sequence
///From: 可以执行数组+complete
let observableFrom = Observable.from(["123", "234", "345"])
observableFrom.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)打印结果:
next(123)
next(234)
next(345)
completed
- Create可以自定义可观察的sequence
- Create操作符传入一个观察者observer,然后调用observer的onNext,onCompleted和onError方法,返回一个可观察的observable序列
///Create: 可以自定义观察事件+complete
let observableCreate = createObservableFunc()
observableCreate.subscribe { (event: Event<Any>) inprint(event)
}.disposed(by: disposeBag)///创建自定义的createObservable
private func createObservableFunc() -> Observable<Any> {return Observable.create { (observer: AnyObserver<Any>) inobserver.onNext("123")observer.onNext("321")//注意:Disposables,带sreturn Disposables.create()}
}
打印结果:
next(123)
next(321)
如果想要completed,则需要加上:observer.onCompleted()
- Range创建一个sequence,会发出这个范围中的从开始到结束的所有事件
///Range: 可以执行某个范围内的
let observableRange = Observable.range(start: 3, count: 3)
observableRange.subscribe { (event: Event<Int>) inprint(event)
}.disposed(by: disposeBag)打印结果:
next(3)
next(4)
next(5)
completed
- RepeatElement重复执行某个事件
///RepeatElement: 重复执行某个事件
let observableRepeatElement = Observable.repeatElement("2")
observableRepeatElement.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)
执行以上代码,恭喜你,程序干崩溃了= =
可以加上take(count):
///RepeatElement: 重复执行某个事件
let observableRepeatElement = Observable.repeatElement("2")
observableRepeatElement.take(3).subscribe { (event: Event<String>) inprint(event)}.disposed(by: disposeBag)打印结果:
next(2)
next(2)
next(2)
completed
4. RxSwift中Subjects
Subjects是什么?
Subject是Observable和Observer之间的桥梁
一个Subject既是一个Observable,也是一个Observer
即可以监听事件,也可以发出事件
Observable:监听事件
Observer:发出事件
PublishSubject、ReplaySubject、BehaviorSubject、BehaviorRelay
PublishSubject
当订阅PublishSubject的时候,只能接收订阅他之后发生的事件
subject.onNext()发出onNext事件,对应的还有OnError()和onCompleted()事件
let publishSub = PublishSubject<String>()
//不接收
publishSub.onNext("0")//订阅事件
publishSub.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)//只能接收订阅后的事件
publishSub.onNext("1")
publishSub.onNext("2")
publishSub.onNext("3")
publishSub.onCompleted()打印结果:
next(1)
next(2)
next(3)
completed
ReplaySubject
当你订阅ReplaySubject的时候,你可以接收到订阅他之后的事件
但也可以接受订阅他之前发出的事件,接受前面几个事件,取决与bufferSize的大小
//bufferSize决定订阅前接收几个。订阅后的都可以接收到
let replaySbu = ReplaySubject<String>.create(bufferSize: 2)
replaySbu.onNext("1-0")
replaySbu.onNext("1-1")
replaySbu.onNext("1-2")
//订阅事件
replaySbu.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)
replaySbu.onNext("1-3")
replaySbu.onNext("1-4")
replaySbu.onNext("1-5")
replaySbu.onCompleted()打印结果:
next(1-1)
next(1-2)
next(1-3)
next(1-4)
next(1-5)
completed
BehaviorSubject
BehaviorSubject会接受到订阅之前的最后一个事件
//behaviorSbu接收订阅前最后一个。订阅后的都可以接收到
let behaviorSbu = BehaviorSubject(value: "1")
behaviorSbu.onNext("2-0")
behaviorSbu.onNext("2-1")
behaviorSbu.onNext("2-2")
//订阅事件
behaviorSbu.subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)
behaviorSbu.onNext("2-3")
behaviorSbu.onNext("2-4")
behaviorSbu.onNext("2-5")
behaviorSbu.onCompleted()打印结果:
next(2-2)
next(2-3)
next(2-4)
next(2-5)
completed
BehaviorRelay
behaviorRelay是BehaviorSubject的一个包装箱
使用的时候,需要调用asObservable()拆箱,里面的value是一个BehaviorSubject
如果Variable准备发出事件,不需要onNext这种方式,而是直接修改对象的value即可
let behaviorRelay = BehaviorRelay(value: "3-1")
behaviorRelay.accept("3-2")
behaviorRelay.accept("3-3")
behaviorRelay.asObservable().subscribe { (event: Event<String>) inprint(event)
}.disposed(by: disposeBag)
behaviorRelay.accept("3-4")
behaviorRelay.accept("3-5")打印结果:
next(3-3)
next(3-4)
next(3-5)
RxSwift在UITableView的使用
方法一:
Model:
struct HeroModel: Codable {var name: Stringvar age: Stringvar description: Stringenum CodingKeys: String, CodingKey {case namecase agecase description = "describe"}
}
ViewModel:
class HeroViewModel {var herosObserrable: BehaviorRelay<[HeroModel]> = {var herosArray: [HeroModel] = [HeroModel]()guardlet path = Bundle.main.path(forResource: "RxSwiftData", ofType: "json"),let jsonData = try? Data(contentsOf: URL(fileURLWithPath: path))else {print("Error loading JSON file")return BehaviorRelay(value: [])}do {let decoder = JSONDecoder()herosArray = try decoder.decode([HeroModel].self, from: jsonData)for hero in herosArray {print(hero)}}catch {print("Error parsing JSON: \(error)")}return BehaviorRelay(value: herosArray)}()
}
extension ViewController {fileprivate func loadData(){//获取VMlet heroVM = HeroViewModel()//订阅VMheroVM.herosObserrable.asObservable().subscribe { (heros: [HeroModel]) inself.herosArray.removeAll()self.herosArray = herosself.myTableView.reloadData()}.disposed(by: disposeBag)}
}extension ViewController: UITableViewDelegate, UITableViewDataSource {func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return herosArray.count}func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {guard let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell") as? MyTableViewCell else {print("Error: Could not dequeue cell as MyTableViewCell")return UITableViewCell()}cell.nameLabel.text = herosArray[indexPath.row].namecell.ageLabel.text = herosArray[indexPath.row].agecell.desLabel.text = herosArray[indexPath.row].descriptionreturn cell}
}private lazy var myTableView: UITableView = {let myTableView = UITableView()myTableView.delegate = selfmyTableView.dataSource = selfmyTableView.register(MyTableViewCell.self, forCellReuseIdentifier: "MyTableViewCell")return myTableView
}()
方法二:
Model、ViewModel同上
extension ViewController {fileprivate func loadData(){let heroVM = HeroViewModel()//直接在这,将监听的数据,直接赋值heroVM.herosObserrable.asObservable().bind(to: myTableView.rx.items(cellIdentifier: "MyTableViewCell", cellType: MyTableViewCell.self)){(row, hero, cell) incell.nameLabel.text = hero.namecell.ageLabel.text = hero.agecell.desLabel.text = hero.description}.disposed(by: disposeBag)}
}
相关文章:
Swift知识点---RxSwift学习
1. 什么是RxSwift RxSwift是Swift函数响应式编程的一个开源库,由Github的ReactiveX组织开发、维护 RxSwift的目的是:让数据/事件流 和 异步任务能够更方便的序列化处理,能够使用Swift进行响应式编程 RxSwift本质上还是观察者模式ÿ…...
驾驭不断发展的人工智能世界
从很多方面来看,历史似乎正在重演。许多企业正争相采用生成式人工智能 (Gen AI),就像它们争相采用云计算一样,原因也是一样的:效率、成本节约和竞争优势。 然而,与云一样,GenAI 仍是一项发展中的技术&…...
冒泡排序——基于Java的实现
简介 冒泡排序(Bubble Sort)是一种简单的排序算法,适用于小规模数据集。其基本思想是通过重复遍历待排序的数组,比较相邻的元素并交换它们的位置,以此将较大的元素逐步“冒泡”到数组的末尾。算法的名称源于其运行过程…...
Mendix 创客访谈录|Mendix赋能汽车零部件行业:重塑架构,加速实践与数字化转型
在当前快速发展的技术时代,汽车行业正经历着前所未有的数字化转型。全球领先的汽车零配件制造商面临着如何利用最新的数字技术优化其制造车间管理的挑战。从设备主数据管理到生产执行工单管理,再到实时监控产量及能耗,需要一个灵活、快速且高…...
船舶机械设备5G智能工厂物联数字孪生平台,推进制造业数字化转型
船舶机械设备5G智能工厂物联数字孪生平台,推进制造业数字化转型。在当今数字化浪潮推动下,船舶制造业正经历着前所未有的变革。为了应对市场的快速变化,提升生产效率,降低成本,并增强国际竞争力,船舶机械设…...
什么是jsonp请求
JSONP(JSON with Padding)是一种解决跨域请求问题的技术。它允许网页从不同的域名请求数据,而不受同源策略的限制。JSONP 通过动态创建 script 标签来实现跨域请求,因为 script 标签不受同源策略的限制。 一、工作原理 客户端&a…...
【C++】STL容器详解【上】
目录 一、STL基本概念 二、STL的六大组件 三、string容器常用操作 3.1 string 容器的基本概念 3.2 string 容器常用操作 3.2.1 string 构造函数 3.2.2 string基本赋值操作 3.2.3 string存取字符操作 3.2.4 string拼接字符操作 3.2.5 string查找和替换 3.2.6 string比…...
助贷行业的三大严峻挑战:贷款中介公司转型债务重组业务
大家是否察觉到一种趋势?现如今,众多贷款辅助服务机构与专注于债务再构的公司之间形成了紧密的“联动”。有的选择将获取的贷款需求转介给债务重组方,有的则直接下场,动用自身资本参与债务重组业务。这一现象背后,究竟…...
力扣第42题 接雨水
前言 记录一下刷题历程 力扣第42题 接雨水 接雨水 原题目:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&…...
轻松录制每一刻:探索2024年免费高清录屏应用
你不会还在用一些社交工具来录屏吧?现在的市面上有不少免费录屏的软件了。别看如软件是免费的,它的功能比起社交工具的录屏功能来说全面的多。这次我就分享几款我用过的录屏工具。 1.福晰录屏大师 链接直达:https://www.foxitsoftware.cn/R…...
【小沐学OpenGL】Ubuntu环境下glfw的安装和使用
文章目录 1、简介1.1 OpenGL简介1.2 glfw简介 2、安装glfw2.1 直接命令二进制安装2.2 源码安装 3、测试glfw3.1 测试1,glfwglew3.2 测试2,glfwglad3.3 测试3 结语 1、简介 1.1 OpenGL简介 OpenGL作为图形界的工业标准,其仅仅定义了一组2D和…...
[数据集][目标检测]汽油检泄漏检测数据集VOC+YOLO格式237张2类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):237 标注数量(xml文件个数):237 标注数量(txt文件个数):237 标注类别…...
图文解析保姆级教程:Postman专业接口测试工具的安装和基本使用
文章目录 1. 引入2. 介绍3. 安装4. 使用 此教程摘选自我的笔记:黑马JavaWeb开发笔记16——请求(postman、简单参数、实体参数、RequestParam映射)想要详细了解更多有关请求各种参数介绍的知识可以移步此篇笔记。 1. 引入 在当前最为主流的开…...
jenkins配置流水线
新建任务,随便选一个名字,选中流水线 配置git的用户名和密码,记录ID,后面配置流水线的时候用。 pipeline {agent anystages {stage(stop app){steps {script {def remote [:]//配置服务地址,用户名和密码remote.na…...
SQL 编程基础
SQL(结构化查询语言)广泛应用于数据库操作,是每个程序员都需要掌握的技能之一。这篇文章将带你从基础入门,了解SQL编程中的常量、变量及流程控制语句。我们将采用简单易懂的语言,结合实际示例,帮助你轻松理…...
sql 中名字 不可以 包含 mysql中 具有 特定意义 的单词
这种sql执行不报错 这种sql执行报错 所以sql中名字不可以使用mysql中具有特定意义的单词 以此文章作为警告,我下次起名字不可以使用 mysql中具有特殊意义的字符 就因为这个导致我搞了一个多小时,急死我了,周五就要前后端联调了。下次千万不…...
分布式部署①
📑打牌 : da pai ge的个人主页 🌤️个人专栏 : da pai ge的博客专栏 ☁️宝剑锋从磨砺出,梅花香自苦寒来 1. 需要部署的服务 Nacos 理论上,应…...
开源可视化大屏superset Docker环境部署
superset 开源可视化大屏Docker环境部署 前言 superset是俄罗斯开源的一款可视化大屏,用于数据可视化探索,含有丰富的图表组件,可以支持接入各种数据源。 接触superset就是想体验下可视化大屏功能,想最快速度安装成功ÿ…...
tomato靶场通关攻略
1.御剑2014找到IP地址 2.dirb扫描目录 3.再次详细扫描目录 4.访问找到的目录文件 进入antibots中 5.搜寻一会再info.php里面发现有东西 6.这个地方貌似可以进行利用 7.查看源代码发现包含include文件上传漏洞 8.网址后面跟?image../../../../../../../etc/passwd 9.既然可以查…...
【Spring Boot 3】【Web】处理跨域资源共享 CORS
【Spring Boot 3】【Web】处理跨域资源共享 CORS 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
