RXSwift源码浅析(二)

简述

本文是对上一篇文章的补充,加上对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.NSObject
extension NSObject: ReactiveCompatible { }
复制代码

协议实现


public protocol ReactiveCompatible {
    
    associatedtype CompatibleType   

    // 类属性 和 对象属性~
    static var rx: Reactive<CompatibleType>.Type { get set }    
    var rx: Reactive<CompatibleType> { get set }               
}

extension ReactiveCompatible {
    public static var rx: Reactive<Self>.Type {
        get {
            return Reactive<Self>.self
        }
        set {
        }
    }
    public var rx: Reactive<Self> {
        get {
            return Reactive(self)
        }
        set {
        }
    }
}
复制代码

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

public struct Reactive<Base> {          
    public let base: Base

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

observe

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

extension Reactive where Base: NSObject {

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

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

//YSD--产生KVO的可观察者
fileprivate final class KVOObservable<Element>: 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<O : ObserverType>(_ 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<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}
复制代码

ObserverType

public protocol ObserverType {
    associatedtype E

    func on(_ event: Event<E>)
}

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<ElementType> : ObserverBase<ElementType> {......}
复制代码

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

单一责任原则

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

最少知道原则

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

结尾

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值