RxSwift 是在 Apple 推出 Swift 后,针对 Swift 语言 ReactiveX 推出 Reactive Extensions 系列一个实现库;除此之外,ReactiveX 还推出了 RxJava,RxAndroid,RxPHP 等蕴含类似思想的框架。
为什么要学习RxSwift
我们知道 C 语言的面向过程,Objective-C、C++ 面向对象编程, Java 的 Spring 框架提出了面向切面编程的思想,学习 RxSwift 不是学习如何使用第三方库,而是学习一种编程思想--函数响应式编程;另外,RxSwift是ReactiveX提出的,其他语言的Rx项目在编程思想上也是一致的,因此如果我们学会了如何使用RxSwift,再去学习Rx.Net, RxJava 或者 RxJS就是小菜一碟,只是语言语法上的差异。这真的就是learn once, apply everywhere.
RxSwift的优点
Composable 可组合,在设计模式中有一种模式叫做组合模式,你可以方便的用不同的组合实现不同的类
Reusable 代码可重用,原因很简单,对应RxSwift,就是一堆Obserable
Declarative 响应式的,因为状态不可变,只有数据变化 Understandable and concise 简洁,容易理解。
Stable 稳定,因为RxSwift写出的代码,单元测试时分方便
Less stateful “无”状态性,因为对于响应式编程,你的应用程序就是一堆数据流
Without leaks 没有泄漏,因为资源管理非常简单
RxSwift实践
1、通过pods引入RxSwift和RxCocoa三方库
RxSwift 是 Swift 语言的函数响应式编程框架。 RxCocoa 则是对苹果原声面向对象 Api 的封装。
pod 'RxSwift'
pod 'RxCocoa'
需要用到 RxSwift 相关内容的类里面,引入模块即可。
import RxSwift
import RxCocoa
2、RxSwift的简单应用
监听UITextField的输入,并把输入的文字展示在UILabel上
(1) 传统做法
成为文本框的代理
textField1.delegate = self
textField2.delegate = self
实现文本框协议
// MARK: - UITextFieldDelegate | |
extension ViewController: UITextFieldDelegate { | |
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { | |
// 判断是哪一个输入框发生改变 | |
if textField == textField1 { | |
print("输入框1 改变") | |
} else { | |
print("输入框2 改变") | |
} | |
return true | |
} | |
} |
这样做可能面临的问题:界面有多个文本框,需要每个都实现代理,并且需要判断是哪一个文本框发生了改变,维护成本比较高,代码可读性差。
(2) RxSwift做法
首先订阅 UITextField,文字输入改变时通过闭包回调,进行打印
TF1.rx.text .subscribe { (str: Event<String?>) in
print(str)
}.addDisposableTo(bag)
把UITextField文字改变的Obserable与UILabel文字改变的Obserale进行绑定
TF1.rx.text .bindTo(label.rx.text).addDisposableTo(bag)
(3) 效果图
3、使用RxSwift重写车务通项目中事件提醒列表
tips:在开始之前请确认安装了RxDataSources这个三方库,如果没有这个库,会崩溃至死。
RxDataSources是使用RxSwift对UITableView和UICollectionView的数据源做了一层包装,引入方法与见步骤1
(1) 为UITableView中的每一个Cell的数据基本结构封装数据模型 RXTestSectionModel包含两个参数,headerName为section的名字,items为这个section中所包含的item数组
struct RXTestItemModel { | |
let licensePlate: String | |
let eventType: String | |
let eventTime: String | |
let isDeal: String | |
} | |
//其实这个可以写成 SectionModel<String, RXTestItemModel> ,但是可读性不好,因此在这个的基础上封装一下sectionModel | |
struct RXTestSectionModel { | |
let headerName: String | |
var items: [Item] | |
} | |
extension RXTestSectionModel: SectionModelType { | |
typealias Item = RXTestItemModel | |
init(original: RXTestSectionModel, items: [Item]) { | |
self = original | |
self.items = items | |
} | |
} |
(2)在视图控制器中声明dataSource属性
let dataSource = RxTableViewSectionedReloadDataSource<RXTestSectionModel>() | |
//(3) 自定义UITableViewCell UI的相关代码在这里略去,在Cell中定义一个item数据模型的变量 | |
var innerItemModel: RXTestItemModel? | |
var itemModel: RXTestItemModel? { | |
set { | |
innerItemModel = newValue | |
licensePlateLb.text = innerItemModel?.licensePlate | |
alarmNameLb.text = innerItemModel?.eventType | |
alarmTimeLb.text = innerItemModel?.eventTime | |
if innerItemModel?.isDeal == "1" { | |
dealStatusImageView.image = UIImage.init(named: "chuli_icon") | |
} else { | |
dealStatusImageView.image = UIImage.init(named: "weichuli_icon") | |
} | |
} | |
get { | |
return innerItemModel | |
} | |
} |
(4) 配置Cell
dataSource.configureCell = { | |
(_, tableView: UITableView, indexPath: IndexPath, eventItemModel: RXTestItemModel) in | |
let cell = tableView.dequeueReusableCell(withIdentifier: RXTestTableViewCell.CellIdentify(), for: indexPath) as! RXTestTableViewCell | |
cell.tag = indexPath.row | |
cell.itemModel = eventItemModel | |
return cell | |
} |
(5) 从接口请求数据并复制给一个[RXTestSectionModel] () 类型的Variable 在这里,itemsList作为一个桥梁,因为普通数据类型无法被当做被观察对象,因此,我们用itemsList.value来接收数据,在把它与tableView的dataSouce进行数据绑定。
//TIP: Variable 中的类型必须是 实例化的数组 要不然在 itemsList.asObservable().bindTo(innertableview.rx.items(dataSource: dataSource)) .addDisposableTo(bag) 绑定中会有错误
var itemsList: Variable = Variable([RXTestSectionModel]()) | |
dataprovider.cwtRxQueryAlarmListWith(targetLicensePlate: "", targetTypeId: "1", pageNo: 0, pageSize: 10).subscribe(onNext: { sectionModel in | |
self.cmcciotStopLoading() | |
print(sectionModel) | |
self.itemsList.value = [sectionModel] | |
}, onError: { | |
errorInfo inself.cmcciotStopLoading() | |
}).addDisposableTo(bag) | |
itemsList.asObservable().bindTo(innertableview.rx.items(dataSource: dataSource)) .addDisposableTo(bag) |
(6)最终效果图
在RxSwift使用和学习的过程中了解到RxSwift语法更加简洁,使用了更少的中间变量和更少的代码,之前8-9句代码RxSwift几乎1句就可以搞定,但是在代码简洁的同时也发现,其代码可读性不高。如果有任何问题,还请各位大神及时指正。