写这篇文章是为了记录下本身在对于RxSwift的学习过程当中的概念理解,操做步骤以及心得体会,以便于在之后复习所用。若是文中有任何错误的地方,还请各位看官老爷们指正...(先捂上脸🤦)html
在学习RxSwift以前,先来了解一下函数响应式编程的思想,咱们能够把函数响应式编程拆开来看,分为函数式编程和响应式编程来理解:react
函数式编程简称FP(Functional Programming),函数式编程就是一种抽象程度很高的编程范式,它将计算机运算看作是数学中函数的计算,而纯粹的函数式编程语言编写的函数没有变量,所以,任意一个函数,只要输入是肯定的,输出就是肯定的,这种纯函数咱们称之为没有反作用。而容许使用变量的程序设计语言,因为函数内部的变量状态不肯定,一样的输入,可能获得不一样的输出,所以,这种函数是有反作用的。git
函数式编程的一个特色就是:容许把函数自己做为参数传入另外一个函数,同时还容许返回一个函数!github
函数表达式: y = f(x) ---> x = f(x) ---> y = f(f(x))编程
下面写一个栗子🌰来理解一下:
有这样一个需求:对于数组[1,2,3,4,5,6,7],首先获取 > 3的数字,获取到的数字以后 + 1,再输出全部数字中的偶数swift
let array = [1,2,3,4,5,6,7]
for num in array{
if num > 3{
let number = num + 1
if (number % 2 == 0) {
print(number)
}
}
}
复制代码
这里咱们利用行为式思路解决了这个需求,下面来换个思路来解决,使用 Array
的filter
方法;数组
let array = [1,2,3,4,5,6,7]
array.filter{ $0 > 3}
.filter{ ($0+1) % 2 == 0 }
.forEach { print($0) }
复制代码
这里 array.filter
函数接受一个闭包类型的参数,filter
方法会对 array
中的每个元素都用传入filter
的闭包调用一遍,根据这个闭包的返回值决定是否将这个元素做为符合条件的元素加入咱们的查找结果中。xcode
简单来讲咱们只须要在传入的闭包中声明好查找的规则,这样咱们就完成整个查找操做的处理了。咱们这里并无告诉程序应该怎么去查找知足条件的元素的方法,而只是声明了一个规则。这样作最大的好处就是可以减小咱们的代码量,让咱们的代码看起来很是的简洁,并且易理解。 这种方式就是函数式编程的一个例子。bash
响应式编程简称RP(Reactive Programming),响应式编程是一种面向数据流和变化传播的异步编程范式。这意味着能够在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值经过数据流进行传播。微信
简单的来讲就是基于事件流的编程方式。事件流就是将要发生事件按照时间顺序排序发生造成的。而当这个事件流产生了返回的数据,能够马上获得通知并调用回调函数去处理数据。(在现实生活中就是:我在家拿起手机预订了一份外卖,而后商家会收到订单,开始制做外卖,制做完成后会通知骑手取餐,骑手接单取餐,而后送餐,到达目的地,外卖送达,订单完成,这样一系列的事件,先称它为事件流,若是在这些事件流进行的过程当中,好比说商家没有出餐,或者骑手没有取餐等等,这些都会致使这个事件流没法完成,而咱们能够根据这个事件流中的任何一个事件的结果来进行响应)
从这个小例子能够看到组成响应式编程的三种动做(数据):事件(数据),错误,结束。经过获得这三个响应式动做,咱们就能够在程序中做出不一样的响应。
这里我的以为有点很重要,就是要对事件进行“预订/监听”,而后才能收到这个事件的反馈。而对于我而言,我就是监听事件的人,也就是“观察者/订阅方”,监听+观察者是否是就是咱们比较熟悉的观察者模式,那么响应式编程就是观察者模式+事件流的控制。
函数响应式编程 FRP(Functional Reactive Programming)是函数式编程与响应式编程相结合起来的,响应式编程思想为体, 函数式编程思想为用。(比较经典的框架就是RAC和RxSwift),经常有人说,FRP能让你的代码像数学同样简洁,业务像流水同样清晰流畅。
首先,ReactiveX
(简写: Rx
) 是一个能够帮助咱们简化异步编程的框架,简单来讲就是基于异步 Event
序列的响应式编程,并提供更优雅的数据绑定,能够时刻响应新的数据同时顺序地处理它们。RxSwift
(ReactiveX for Swift)
,就是ReactiveX
的Swift
版本ReactiveX
家族很是强大,就如同‘毒液家族’同样的强大,除了我后面会学习的 RxSwift
以外,还有 RAC(ReactiveCocoa), RxJava, RxJS, RxKotlin, Rx.NET
...等等.
Rx.xcodeproj
拖拽至工程中,Project -> Targets -> General -> Embedded Binaries
配置项, RxSwift.framework
、RxCocoa.framework
添加进来便可RxSwift
的地方import
进来# Podfile
use_frameworks!
target 'YOUR_TARGET_NAME' do
pod 'RxSwift', '~> 5.0'
pod 'RxCocoa', '~> 5.0'
end
复制代码
替换 YOUR_TARGET_NAME
而后在 Podfile
目录下, 终端输入:
$ pod install
复制代码
🗣🗣🗣这里说明一下为何会导入
RxSwift
和RxCocoa
两个库,它们的做用分别是:
RxSwift
:它只是基于Swift
语言的Rx
标准实现接口库,因此RxSwift
里不包含任何Cocoa
或者UI
方面的类。RxCocoa
:是基于RxSwift
针对于iOS
开发的一个库,它经过Extension
的方法给原生的好比UI
控件添加了Rx
的特性,使得咱们更容易订阅和响应这些控件的事件。
Rx
就是和复合的代名词Rx
是彻底经过单元测试的到底是不是这样的呢,下面经过一些经常使用的方式来验证一下:
func setupKVO() {
self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
person.name = "\(person.name) +"
// print(person.name)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("响应")
print(change as Any)
}
deinit {
self.removeObserver(self.person, forKeyPath: "name", context: nil)
}
复制代码
func setupKVO() {
self.person.rx.observeWeakly(String.self, "name")
.subscribe(onNext: { (value) in
print(value as Any)
})
.disposed(by: disposeBag)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
person.name = "\(person.name) +"
// print(person.name)
}
复制代码
是否是感受
RxSwift
版本的KVO
写的代码更少了,并且也不用去实现观察者的代理方法,不用关心是否遗漏removeObserver
方法。
func setupButton() {
button.addTarget(self, action: #selector(didClickButton), for: .touchUpInside)
}
@objc func didClickButton(){
print("点我干什么")
}
复制代码
func setupButton() {
self.button.rx.tap
.subscribe(onNext: { () in
print("点击事件")
})
.disposed(by: disposeBag)
}
复制代码
不须要实现
Target Action
,代码更加简单了
class ViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("contentOffset: \(scrollView.contentOffset)")
}
}
复制代码
class ViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
scrollView.rx.contentOffset
.subscribe(onNext: { contentOffset in
print("contentOffset: \(contentOffset)")
})
.disposed(by: disposeBag)
}
}
复制代码
不须要实现代理方法啦,能够直接获取到
scrollview
的偏移
var testObserver: NSObjectProtocol!
override func viewDidLoad() {
super.viewDidLoad()
testObserver = NotificationCenter.default.addObserver(
forName: .UIApplicationWillEnterForeground,
object: nil, queue: nil) { (notification) in
print("Application Will Enter Foreground")
}
}
deinit {
NotificationCenter.default.removeObserver(testObserver)
}
复制代码
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.rx
.notification(.UIApplicationWillEnterForeground)
.subscribe(onNext: { (notification) in
print("Application Will Enter Foreground")
})
.disposed(by: disposeBag)
}
复制代码
不须要去关注是否已经移除了通知,不会由于没有移除通知而出现崩溃
func setupGestureRecognizer(){
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(singleTap(_:)))
self.label.addGestureRecognizer(tap)
self.label.isUserInteractionEnabled = true
}
@objc func singleTap(_ tapGesture: UITapGestureRecognizer) {
print("点我干吗")
}
复制代码
func setupGestureRecognizer(){
let tap = UITapGestureRecognizer()
self.label.addGestureRecognizer(tap)
self.label.isUserInteractionEnabled = true
tap.rx.event.subscribe(onNext: { (tap) in
print(tap.view)
})
.disposed(by: disposeBag)
}
复制代码
少写了手势触发实现的方法,代码更简介了
var testtimer = Timer()
func setupTimer() {
testtimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UpdateTimer), userInfo: nil, repeats: true)
testtimer.fire();
RunLoop.current.add(testtimer, forMode: .common)
}
@objc func UpdateTimer() {
print("timer start")
}
复制代码
var timer: Observable<Int>!
func setupTimer() {
timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
timer.subscribe(onNext: { (num) in
print(num)
})
.disposed(by: disposeBag)
}
复制代码
这里
timer
更好地是不用考虑页面上的Scrollview
对timer
的影响
看完这些小例子🌰以后,以为RxSwift
比通常的Swift
写法要简单好多,简直就是“骚通常的操做”。
在前面的概念介绍中大概已经知道了ReactiveX
是基于异步 Event
序列的响应式编程, 并提供更优雅的数据绑定,能够时刻响应新的数据同时顺序地处理它们,既然要响应数据,就还须要一个观察者。
RxSwift 核心概念就能够理解为一个观察者(Observer
)订阅一个可被观察序列(Observable
)。观察者对可被观察序列发射的事件(Event
)或事件序列做出响应。
先来理解一下这三个类的概念:
Observable<T>
这个类就是 Rx
框架的基础,咱们能够称它为可观察序列。它的做用就是能够异步地产生一系列的 Event
(事件),即一个 Observable<T>
对象会随着时间推移不按期地发出 event(element : T)
这样一个东西。Event
还能够携带数据,它的泛型 <T>
就是用来指定这个 Event
携带的数据的类型。Observer
(订阅者)来订阅它,这样这个订阅者才能收到 Observable<T>
不时发出的 Event
。既然Observable
是一个可被观察的序列,能够异步地产生一系列的 Event
,那么查看RxSwift/Event.swift
源码能够发现
public enum Event<Element> {
/// Next element is produced.
case next(Element)
/// Sequence terminated with an error.
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
复制代码
Event
被定义成一个枚举值,这也就是说一个Observable
可观察序列能够发出三种不一样类型的Event
事件:
next
事件就是那个能够携带数据 <T>
的事件,能够说它就是一个普通事件error
事件表示一个错误,它能够携带具体的错误内容,一旦 Observable
发出了 error
event,则这个
Observable就等于终止了,之后它不再会发出
event` 事件了。completed
事件表示 Observable
发出的事件正常地结束了,跟 error
同样,一旦 Observable
发出了 completed event
,则这个 Observable
就等于终止了,之后它不再会发出 event
事件了序列监听有三个步骤:1.建立序列,2订阅序列,3.发送信号。当建立序列,并订阅了序列后,只要某个事件发送了序列消息,就能够在序列订阅的闭包里面监听到发送的消息。
下面建立一个可观察序列来感觉一下:
//第一步:建立序列
//在create()函数中传入一个闭包,任务是对每个过来的订阅进行处理
let ob = Observable<Any>.create { (observer) -> Disposable in
// 第三步:发送信号(onCompleted和onError只能发送一个)
observer.onNext("你好骚啊")
observer.onCompleted()
// observer.onError(NSError.init(domain: "loser", code: 10010, userInfo: nil))
return Disposables.create()
//第二步:订阅信息
//当咱们订阅了Observable的消息后,只要Observable的事件触发,都会经过onNext这个闭包告诉咱们。
let _ = ob.subscribe(onNext: { (text) in
print("订阅到:\(text)") //这里会监听到订阅的Observable事件
}, onError: { (error) in
print("error: \(error)") //当发生错误时,会回调这里
}, onCompleted: { // 当序列执行完毕时,会回调这里。
print("完成")
}) {
print("销毁")
}
.disposed(by: disposeBag)
复制代码
DisposeBag
:做用是Rx
在视图控制器或者其持有者将要销毁的时候,自动释法掉绑定在它上面的资源。它是经过相似“订阅处置机制”方式实现(相似于NotificationCenter
的removeObserver
)。
这就算是RxSwift
响应式的核心逻辑了,这里有点疑惑就是:为何观察者发出的信号,可观察序列可以订阅到呢?
未完待续......
注:感谢下面的参考文档
书籍目录——获取地址加小编微信拉你进iOS开发群:17512010526
收录:原文地址