【iOS进阶】RxSwift

340 阅读5分钟

基础

RxSwift简介

  1. 复合

  2. 复用

  3. 清晰:声明不可变更

  4. 易用:抽象了异步编程

  5. 稳定

函数响应式编程

函数式编程

  • 函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础也是lamda运算,而且lamda运算的函数可以接受函数当作输入(参数)和输出(返回值)

  • 指令式编程,函数响应式编程强调函数的计算指令的执行更重要

  • 过程化编程,函数响应式编程里函数的计算可以随时调用

响应式编程

  • 一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

  • 数据流:只能以事先规定好的顺序被覆去一次的数据的一个序列

  • 变化传播:类似观察者模式,变化了要通知别人

对比

我们有一个数组let arr = [0,1,2,3,4,5]。需求:1. 获取所有>=3的数字。2. 所有的数字+1 。3. 打印所有偶数。

  • 常规写法


var newArr1:[Int] = []

for item in arr {

    guard item >= 3,

          (item + 1) % 2 == 0 else {

        continue

    }

    newArr1.append(item)

}

  


可以看出来可读性不强,且乍一看不是很能从代码中看出需求。

  • 函数式编程


var newArr2:[Int] = []

arr.filter{ $0 >= 3 }

    .filter{ ($0 + 1) % 2 == 0 }

    .forEach{ newArr2.append($0) }

  


是不是清晰明了!

KVO

前面已经可以看出函数式编程的好处,那么问题来了,假如我们有一个变量var a = 10,且希望另一个变量为a的两倍var b = a * 2,此时肯定是能得出b为20,但是如果a变化,b是不会跟着变化的,这就需要我们的KVO机制。


/*

注:

1. 需要添加观察者的对象类型必须继承自NSObject

2. 需要被观察的属性必须加上@objc和dynamic

*/

class DemoObject : NSObject{

   @objc dynamic var name: String = "Letty"

    var age: Int = 24

}

  


var obj: DemoObject = DemoObject()

  


// 添加观察者

self.addObserver(self.obj,

                 forKeyPath: "name",

                 options: .new,

                 context: nil)

// KVO回调

override func observeValue(forKeyPath keyPath: String?,

                                 of object: Any?,

                                 change: [NSKeyValueChangeKey : Any]?,

                                 context: UnsafeMutableRawPointer?) {

    guard keyPath == "name" else {

        return

    }

    print(change as Any)

}

  


// 注:deinit需要移除观察者

deinit {

        self.obj.removeObserver(self,

                            forKeyPath: "name")

    }

  


当值发生变化

https://oscimg.oschina.net/oscnet/up-8fe03552d354ae43cf5e32f0b071629bd34.png

可以监听到变化。

思考

有没有觉得这样其实也很不方便?添加观察者的地方和处理逻辑需要分开写。且如果要观察的对象一多就很容易混淆。这就要引出我们的RxSwift。

RxSwift

上述情况的RxSwift写法,可以看出你需要对值的变化的任何处理都可以放在同一个地方,是不是清晰明白了很多!!


// 类似一个垃圾袋,回收资源时一个一个回收,就不需要我们手动回收了

let disposeBag = DisposeBag()

// 添加到响应序列DisposeBag中

self.obj.rx.observeWeakly(String.self,

                          "name")

            .subscribe(onNext: { value in

                print(value as Any)

            }, onError: { error in

                print(error.localizedDescription)

            }, onCompleted: {

                print("onCompleted")

            }, onDisposed: {

                print("onDisposed")

            })

            .disposed(by: disposeBag)

Observable可观察序列

  1. 类似sequence,next即为任务链

  2. 无穷序列


// 不断订阅

let ob = Observable<Element>.interval({RxTimeInterval},

                                      <SchedulerType>)

  1. 有穷序列


let ob = Observable.just([1,2,3])

ob.subscribe { num in

    print(num)

} onCompleted: {

    print("订阅完成")

}

  


核心逻辑

重点步骤

  1. 创建序列


let yk_observable = Observable<Any>.create { (observer) -> Disposable in

    // 3. 发送信号

    observer.onNext("发送值!")

    observer.onError(NSError(domain: "YKERROR",

                             code: 404,

                             userInfo: nil))

    return Disposables.create()

}

  


  1. 订阅信号


let yk_disposable = yk_observable.subscribe { anyElement in

    // 订阅到值

    print("订阅到值:\\(anyElement)")

} onError: { error in

    // 错误

    print(error)

} onCompleted: {

    // 完成

    print("onCompleted")

} onDisposed: {

    // 销毁

    print("onDisposed")

}

  


  1. 发送信号(在创建序列的闭包中处理)。也就是说,在创建序列的闭包中传入的操作,都会分别触发第二步中观察者的操作。


observer.onNext("发送值!")

observer.onError(NSError(domain: "YKERROR",

                         code: 404,

                         userInfo: nil))

return Disposables.create()

observer.onNext("发送值!")

observer.onError(NSError(domain: "YKERROR",

                         code: 404,

                         userInfo: nil))

return Disposables.create()

  


流程探索

  1. 我们从create方法入手,可以看到该方法会创建一个AnonymousObservable类型的对象,并保存传入的【何时/如何调用onNext/onError等方法】的闭包。


/ *

- parameter subscribe: 得到的可观察序列的subscribe方法的实现

- returns:Observable类型,为传入的subscribe闭包指定实现的可观察序列。

*/

public static func create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable)

-> Observable<Element> {

// 创建了一个匿名内部类AnonymousObservable 继承自Producer

    AnonymousObservable(subscribe)

}

  


AnonymousObservable在初始化时,保存了subscribe闭包为属性【记录操作】,也就是将create方法传入的 (AnyObserver<Element>) -> Disposable)存储下来。


init(_ subscribeHandler: @escaping SubscribeHandler) {

    self.subscribeHandler = subscribeHandler

}

  


  1. 流程第二步:subscribe探索。第一步返回的是Observable,在其父类ObservableType的扩展方法中【ObservableType+Extensions.swift】可以找到上述订阅信号的方法实现。


/**

 向可观察序列订阅元素处理程序、错误处理程序、完成处理程序和处置处理程序。

 - parameter onNext: 可观察序列中的每个元素调用的操作

 - parameter onError: 在可观察序列错误终止时调用的操作

 - parameter onCompleted: 可观察序列优雅终止时调用的动作。

 - parameter onDisposed: 在任何类型的序列终止时调用的操作(完成/错误/取消订阅)

 - returns: Disposable类型。订阅对象,用于取消对可观察序列的订阅。

 */

public func subscribe(

    onNext: ((Element) -> Void)? = nil,

    onError: ((Swift.Error) -> Void)? = nil,

    onCompleted: (() -> Void)? = nil,

    onDisposed: (() -> Void)? = nil

) -> Disposable {

  


在方法实现中,会创建一个Disposables订阅者类型的对象,并保存传入的【当捕获到值/error/事件完成的消息时要做什么处理】的闭包。


// 1. 创建Disposable对象,传入【事件处理的闭包】,创建了一个内部的AnonymousObserver

let observer = AnonymousObserver<Element> { event in

···

}

// 2. 创建Disposables对象,传入的两个参数分别是【将自身添加到观察者序列】【第一步中保存了操作的Disposable对象】

return Disposables.create(

    self.asObservable().subscribe(observer),

    disposable

)

  


忍不住疑惑


self.asObservable().subscribe(observer)

这一步做了什么。进入源码可以看出:self即为第一步中我们创建的AnonymousObservable对象,其调用asObservable()方法返回的是自身,而在subscribe方法中我们也可以根据断点来看

https://oscimg.oschina.net/oscnet/up-2de27d168bc1ee600aeb00379f02355ba23.png

在当前线程调用自身的run方法。


func run(_ parent: Parent) -> Disposable {

    parent.subscribeHandler(AnyObserver(self))

}

  


到这里就很清晰了,如果看晕了的话我们可以通过lldb来看一下这是什么。

https://oscimg.oschina.net/oscnet/up-3fa77fe579fa664dc42d1673cfb6ed83a6b.png

也就是说会调用我们在第一步中创建的AnonymousObservable对象保存的闭包中的代码。根据调用堆栈也可以清晰的看出。

https://oscimg.oschina.net/oscnet/up-9072cdc51268fa9dd8838bdd867fb96dff6.png