当前位置: 首页 > article >正文

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>) in
	print(event)
}

上述方法会有一个标黄的警告:Result of call to ‘subscribe’ is unused
修改方法:

private lazy var disposeBag: DisposeBag = DisposeBag()

self.button.rx.tap.subscribe { (event: Event<Void>) in
      print(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?>) in
	print(event.element)//获取信息
}.disposed(by: disposeBag)

这种方法,获取的event有两个Optional包裹着,使用起来不方便

方法三:
self.textField.rx.text.subscribe { (myString: String?) in
    print(myString)//获取的是Optional类型
} onError: { error in
    print(error)
} onCompleted: {
    print("onCompleted")
} onDisposed: {
    print("onDisposed")
}.disposed(by: disposeBag)

以上可以简化:

self.textField.rx.text.subscribe { (myString: String?) in
    print(myString)//获取的是Optional类型
}.disposed(by: disposeBag)

监听Label中的文字

UITextField文字输入,然后Label显示输入的文字

方法一:
self.textField.rx.text.subscribe { (myString: String?) in
    print(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?) in
	print(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) in
	print(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>) in
	print(event)
}.disposed(by: disposeBag)
  • Empty创建一个空的sequence,只能发出一个completed事件
 //只执行completed
let observableEmpty = Observable<String>.empty()
observableEmpty.subscribe { (event: Event<String>) in
	print(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>) in
	print(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>) in
    print(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>) in
	print(event)
}.disposed(by: disposeBag)

///创建自定义的createObservable
private func createObservableFunc() -> Observable<Any> {
	return Observable.create { (observer: AnyObserver<Any>) in
		observer.onNext("123")
        observer.onNext("321")
        //注意:Disposables,带s
        return 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>) in
    print(event)
}.disposed(by: disposeBag)

打印结果:
next(3)
next(4)
next(5)
completed
  • RepeatElement重复执行某个事件
///RepeatElement: 重复执行某个事件
let observableRepeatElement = Observable.repeatElement("2")
observableRepeatElement.subscribe { (event: Event<String>) in
    print(event)
}.disposed(by: disposeBag)

执行以上代码,恭喜你,程序干崩溃了= =

可以加上take(count)

///RepeatElement: 重复执行某个事件
let observableRepeatElement = Observable.repeatElement("2")
observableRepeatElement
    .take(3)
    .subscribe { (event: Event<String>) in
        print(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>) in
    print(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>) in
    print(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>) in
    print(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>) in
    print(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: String
    var age: String
    var description: String
    
    enum CodingKeys: String, CodingKey {
        case name
        case age
        case description = "describe"
    }
}

ViewModel:

class HeroViewModel {
    var herosObserrable: BehaviorRelay<[HeroModel]> = {
        var herosArray: [HeroModel] = [HeroModel]()
        
        guard
            let 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(){
    	//获取VM
        let heroVM = HeroViewModel()
        //订阅VM
        heroVM.herosObserrable.asObservable().subscribe { (heros: [HeroModel]) in
            self.herosArray.removeAll()
            self.herosArray = heros
            self.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].name
        cell.ageLabel.text = herosArray[indexPath.row].age
        cell.desLabel.text = herosArray[indexPath.row].description
        
        return cell
    }
}

private lazy var myTableView: UITableView = {
    let myTableView = UITableView()
    myTableView.delegate = self
    myTableView.dataSource = self
    myTableView.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) in
                
                cell.nameLabel.text = hero.name
                cell.ageLabel.text = hero.age
                cell.desLabel.text = hero.description
            }.disposed(by: disposeBag)
    }
}

http://www.kler.cn/news/293564.html

相关文章:

  • Centos配置双网卡绑定(bond)
  • Apache Tomcat 6.0.45 下载、安装和配置教程
  • YOLO缺陷检测学习笔记(3)
  • 【西安交通大学】高等计算机网络与通信期末题(回忆版)
  • 单片机学习笔记
  • 在VMware中的centos stream 9上用packstack安装openstack的单机版
  • 用于资产定价的FAFA三因素模型的案例实现
  • 如何在VSCode中同时打开多个页面?
  • 适用于手机/相机/电脑的照片恢复应用程序
  • 结合Python与GUI实现比赛预测与游戏数据分析
  • 微信小程序显示后台文章副文本,图片和视频正常显示
  • 考拉悠然董事长申恒涛受邀出席2024AGIC深圳通用人工智能大会
  • python3查看es集群中每个索引的分片和副本配置
  • 快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
  • [数据集][目标检测]水面垃圾检测数据集VOC+YOLO格式2027张1类别
  • 基础学习之——git 的使用方式
  • CTFHub技能树-Git泄漏-Stash
  • 前后端时间传递之注解
  • K8s中pod控制器
  • 影响画布微信小程序canvas及skyline和webview用户界面布局的关键流程
  • 如何利用ChatGPT提升学术论文讨论部分的撰写质量和效率
  • 图像仿射变换及其逆变换【Python实现】
  • 如何恢复格式化的 Android 智能手机
  • 使用NetBackup GUI 图形化进行oracle备份和恢复
  • 日志轮转方案和脚本
  • EvoSuite使用总结
  • Java+Swing+sqlserver学生成绩管理系统
  • springboot中上传图片到阿里云的oss云存储
  • CSS学习9[重点]--盒子模型大小、布局稳定性、CSS3盒模型以及盒子阴影
  • 端侧 ChatGPT 时刻到来!面壁小钢炮 3.0 重磅发布