正文
简述
本文是对上一篇文章的补充,加上对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,
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) {
_ = Resources.incrementTotal()
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 {
_ = Resources.decrementTotal()
}
}
相对应它的父类就是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 for KeyPath: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 for KeyPath: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
的分析~ 如果老大的需求没下来 应该很快吧~. 文中要有不准确的地方,请多多指正呀(๑•ᴗ•๑)
才发现掘金可以加封面大图~~~蓝瘦~