博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RXSwift源码浅析(二)
阅读量:7009 次
发布时间:2019-06-28

本文共 7666 字,大约阅读时间需要 25 分钟。

简述

本文是对上一篇文章的补充,加上对KVO实现的简要分析 和 自己的一些思考,可能会有不够准确的地方还望多多指正,共同学习~~

框架结构

在上篇文章中是从具体实现的角度分析Observable的使用实现,接下来从一个高一点的角度来分析RXSwift.

效果

无论是Observable,还是KVO,通知,按钮点击....,在本质上我认为可将这一切看为这样一个过程~

以通知为例子, 在程序中某个地方发出了事件(例如键盘弹出),这就是
事件源. 然后这个
事件传递(系统发出键盘弹出的通知). 最后程序的某处
响应了这个事件(比如我们监听到这个通知,然后将控件上移). 我认为RXSwift就是为了让大家更方便的实现这样的过程~

而RXSwift的结构就大概是这样的

结构简图

1,事件源

例如
create函数~

2,响应

为了简洁,我并没有加入资源释放那部分, 具体的可以参照进行对比的来看, 中介在事件源中接受事件,在响应中输出事件.

接下啦我再以KVO的实现细节 再来展示一下这个结构~~

KVO实现细节

下面是一段日常使用RXSwift的代码~

class Test: NSObject {    @objc var name:String!}class ViewController: UIViewController {    @objc var obj:Test!    var disposeBag = DisposeBag()        override func viewDidLoad() {        super.viewDidLoad()        obj = Test()        obj.rx.observe(String.self, #keyPath(Test.name)).subscribe { (eve) in            print(eve)        }.disposed(by: self.disposeBag)    }}复制代码

事件源

rx

首先第一步是调用对象的rx属性, rx来源于 对NSObject的扩展协议~

import class Foundation.NSObjectextension NSObject: ReactiveCompatible { }复制代码

协议实现

public protocol ReactiveCompatible {        associatedtype CompatibleType       // 类属性 和 对象属性~    static var rx: Reactive
.Type { get set } var rx: Reactive
{ get set } }extension ReactiveCompatible { public static var rx: Reactive
.Type { get { return Reactive
.self } set { } } public var rx: Reactive
{ get { return Reactive(self) } set { } }}复制代码

这里其实是为了将当前对象封装为一个**Reactive**结构体

public struct Reactive {              public let base: Base    public init(_ base: Base) {        self.base = base    }}复制代码

observe

一般我们调用的是这个扩展方法

extension Reactive where Base: NSObject {    public func observe
(_ type: E.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable
{ return KVOObservable(object: base, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable() }}复制代码

observe方法首先创建一个KVOObservable对象~

//YSD--产生KVO的可观察者fileprivate final class KVOObservable
: ObservableType, KVOObservableProtocol { typealias E = Element? unowned var target: AnyObject var strongTarget: AnyObject? var keyPath: String var options: KeyValueObservingOptions var retainTarget: Bool //初始化方法 init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) { self.target = object self.keyPath = keyPath self.options = options self.retainTarget = retainTarget if retainTarget { self.strongTarget = object } } //订阅方法~~~ func subscribe
(_ observer: O) -> Disposable where O.E == Element? { let observer = KVOObserver(parent: self) { (value) in if value as? NSNull != nil { observer.on(.next(nil)) return } observer.on(.next(value as? Element)) } return Disposables.create(with: observer.dispose) }}..............fileprivate protocol KVOObservableProtocol { var target: AnyObject { get } var keyPath: String { get } var retainTarget: Bool { get } var options: KeyValueObservingOptions { get }}复制代码

KVOObservable对象遵守ObservableType协议,所以可以调用asObsevable()方法, KVOObservableProtocol协议限定它持有这些KVO 必须的属性~,因为在本质上,还是调用OC的KVO实现~

动态语言还是爽呀~

订阅方法

订阅时也就是上面重载的方法~ 首先还是创建一个观察者,来持有 事件响应的闭包~

let observer = KVOObserver(parent: self) { (value) in            if value as? NSNull != nil {                observer.on(.next(nil))                return            }                       observer.on(.next(value as? Element))        }复制代码

然而事件是从哪里发出的呢~

fileprivate final class KVOObserver    : _RXKVOObserver    , Disposable {        typealias Callback = (Any?) -> Void    var retainSelf: KVOObserver? = nil    init(parent: KVOObservableProtocol, callback: @escaping Callback) {        #if TRACE_RESOURCES            _ = Resources.incrementTotal()        #endif        super.init(target: parent.target, retainTarget: parent.retainTarget, keyPath: parent.keyPath, options: parent.options.nsOptions, callback: callback)        //因为 可观察者并不强引用它,所以通过循环引用 保持自己不被回收        self.retainSelf = self    }//只用调用dispose后才会回收,所以大家注意 不要因为偷懒不好好使用disposeBag(๑•ᴗ•๑)    override func dispose() {        super.dispose()             self.retainSelf = nil    }    deinit {        #if TRACE_RESOURCES            _ = Resources.decrementTotal()        #endif    }}复制代码

相对应它的父类就是OC实现的~

@interface _RXKVOObserver ()                    //和weak差不多, 但是weak释放了为变为nil 它不会 会因为野指针的使用而崩溃@property (nonatomic, unsafe_unretained) id            target;@property (nonatomic, strong           ) id            retainedTarget;@property (nonatomic, copy             ) NSString     *keyPath;@property (nonatomic, copy             ) void (^callback)(id);@end@implementation _RXKVOObserver-(instancetype)initWithTarget:(id)target                 retainTarget:(BOOL)retainTarget                      keyPath:(NSString*)keyPath                      options:(NSKeyValueObservingOptions)options                     callback:(void (^)(id))callback {    self = [super init];    if (!self) return nil;        self.target = target;    if (retainTarget) {        self.retainedTarget = target;    }    self.keyPath = keyPath;    self.callback = callback;        [self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];        return self;}//常规的操作,将监听到的新值作为block参数返回-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {    @synchronized(self) {        self.callback(change[NSKeyValueChangeNewKey]);    }}-(void)dispose {    [self.target removeObserver:self forKeyPath:self.keyPath context:nil];    self.target = nil;    self.retainedTarget = nil;}复制代码

将KVO的newValue作为参数传入 callBack闭包中~

所以RXSwift对于 KVO的实现就比较简单了,观察者既是事件源 也是 中介 总的来说是将 普通的KVO写法 进行封装,纳入自己的体系之下

反思~

学而不思则罔,思而不学则殆. 所以看完大神的源码一定要反思~ 不然除了框架用的更熟练 跟没看一样~

面向协议

我认为RXSwift就是一个我们学习面向协议编程(Protocol-oriented programming)的好例子~, 通过协议 我们可以很好的解决继承带来的种种弊端~

1, 可以实现在OC和Swift不允许的 多继承~ 2, 避免基类受制于子类, 实现依赖倒转, 让子类受制于协议~

在RXSwift中有一些重要的协议ObservableType,ObserverType,Disposable

ObservableType

public protocol ObservableType : ObservableConvertibleType {    func subscribe
(_ observer: O) -> Disposable where O.E == E}复制代码

ObserverType

public protocol ObserverType {    associatedtype E    func on(_ event: Event
)}extension ObserverType { public func onNext(_ element: E) { on(.next(element)) } public func onCompleted() { on(.completed) } public func onError(_ error: Swift.Error) { on(.error(error)) }}复制代码

Disposable

public protocol Disposable {    public func dispose()}复制代码

通过这些协议 将各个角色类的行为加以限制, 而各个协议之间是互相对接的,这样即使各个类不相同,只要大家遵守相同的协议,就可以在这个体系下畅通无阻~ . 打个简单的例子就是 弹幕功能

从服务器发来的需要展示的消息是各种各样的(普通弹幕,礼物弹幕,贵族弹幕,管理信息弹幕~~~~),当其实在显示的时候,只需要显示文字和图片而已~ 这样让 消息都遵守可以获取文字图片的协议,这样不管发过来什么消息 都可以正常显示~ 当然使用继承也可以实现,但是若我们要加新的消息类型(礼物火箭),这时继承要改基类,乱改基类很有可能会影响到其他子类导致Bug,而协议只需要扩展,或者限定类型的扩展~

当然这不是说让大家不要用继承,在RXSwift中也是有继承的~

final class AnonymousObserver
: ObserverBase
{......}复制代码

所以我个人是这样认为的,POP这是纲领,不是方案~ 使用的时候要灵活,小范围,少变动的用继承,大范围,多变化的用协议

单一责任原则

在搭架子的时候就将 角色责任 区分好~ 就像最上面的图示一样,,避免类兼数值. 这样无论是对Bug的定位,还是对项目架构的贯彻 都是有好处的~(๑•ᴗ•๑)

最少知道原则

也就是耦合度的问题,我觉得大家都知道写代码要 高内聚,低耦合. 但是怎么做呢~ 在RXSwift中是这样做的,也就是POP 各个角色间通过协议沟通(我到目前为止展示出来的方法,基本上都是协议上的方法),而类通过遵守协议对协议内容进行实现. 这样 耦合的就只有协议,而类只专注对协议的实现

结尾

暂时就反思了这么多~然后有内容再补充吧,下篇就写 flatMap的分析~ 如果老大的需求没下来 应该很快吧~. 文中要有不准确的地方,请多多指正呀(๑•ᴗ•๑)

才发现掘金可以加封面大图~~~蓝瘦~

转载地址:http://zzxtl.baihongyu.com/

你可能感兴趣的文章
logstash之filter处理中括号包围的内容
查看>>
彩票的思考
查看>>
转帖:解决System.Data.OracleClient requires Oracle client software version 8.1.7 or greater
查看>>
Visual Studio Code Name "Orcas" Beta 1发布
查看>>
开发nodejs模块并发布到npm的简单示例
查看>>
SSH login without password
查看>>
你应该如何更好地利用搜索引擎
查看>>
转载:Window Azure 中的Web Role详解
查看>>
自启动程序详解
查看>>
转 nutch网页快照乱码解决方法
查看>>
HDU 2426 Interesting Housing Problem
查看>>
SQLSqlserver中如何将一列数据,不重复的拼接成一个字符串
查看>>
[Java 泥水匠] Java Components 之二:算法篇之项目实践中的位运算符(有你不懂的哦)...
查看>>
讨论:怎样加快android的开机时间
查看>>
oh my zsh设置
查看>>
解读ASP.NET 5 & MVC6系列(5):Configuration配置信息管理
查看>>
【原创】JDK动态代理,此次之后,永生难忘。
查看>>
collection的框架结构
查看>>
c++中的对象复制
查看>>
ubuntu下linux内核源码阅读工具和调试方法总结
查看>>