委托代理(delegate
) iOS 开发中十分常见。不管是使用系统自带的库,还是一些第三方组件时,我们总能看到 delegate
的身影。使用 delegate
可以实现代码的松耦合,减少代码复杂度。但如果我们项目中使用 RxSwift
,那么原先的 delegate
方式与我们链式编程方式就不相称了。
解决办法就是将代理方法进行一层 Rx
封装,这样做不仅会减少许多不必要的工作(比如原先需要遵守不同的代理,并且要实现相应的代理方法),还会使得代码的聚合度更高,更加符合响应式编程的规范。
其实在 RxCocoa 源码中我们也可以发现,它已经对标准的 Cocoa
做了大量的封装(比如 tableView
的 itemSelected
)。下面我将通过样例演示如何将代理方法进行 Rx
化。
一、对 Delegate进行Rx封装原理
1,DelegateProxy
(1)DelegateProxy
是代理委托,我们可以将它看作是代理的代理。
(2)DelegateProxy
的作用是做为一个中间代理,他会先把系统的 delegate
对象保存一份,然后拦截 delegate
的方法。也就是说在每次触发 delegate
方法之前,会先调用 DelegateProxy
这边对应的方法,我们可以在这里发射序列给多个订阅者。
2,流程图
这里以 UIScrollView
为例,Delegate proxy
便是其代理委托,它遵守 DelegateProxyType
与 UIScrollViewDelegate
,并能响应 UIScrollViewDelegate
的代理方法,这里我们可以为代理委托设计它所要响应的方法(即为订阅者发送观察序列)。
/***
+-------------------------------------------+
| |
| UIView subclass (UIScrollView) |
| |
+-----------+-------------------------------+
|
| Delegate
|
|
+-----------v-------------------------------+
| |
| Delegate proxy : DelegateProxyType +-----+----> Observable<T1>
| , UIScrollViewDelegate | |
+-----------+-------------------------------+ +----> Observable<T2>
| |
| +----> Observable<T3>
| |
| forwards events |
| to custom delegate |
| v
+-----------v-------------------------------+
| |
| Custom delegate (UIScrollViewDelegate) |
| |
+-------------------------------------------+
**/
二 自定义代理实现代理的一对多1实现一个需要代理的类
// // Car.swift // Pod11 // // Created by dzq_mac on 2020/1/13. // Copyright © 2020 dzq_mac. All rights reserved. // import UIKit import RxSwift import CoreLocation @objc public protocol CarOilProtocol: AnyObject { @discardableResult func oil80(name:String) -> String @discardableResult func oil50(name:String) -> String // func oil20(whoCar:String) // func oil10(whoCar:String) } extension CarOilProtocol { public func oil10(whoCar:String){ } public func oil20(whoCar:String){ } } public class CarCar:ReactiveCompatible { var name :String var oilQulity:Int32 = 100 var disposeBag:DisposeBag = DisposeBag() var timer :Observable<Int>? public weak var delegate:CarOilProtocol? init(name:String) { self.name = name } func startRun(){ timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance) timer?.subscribe(onNext: {[weak self] (i) in // print(i) self?.oilQulity -= 1 if self?.oilQulity == 80 { self?.delegate?.oil80(name: self?.name ?? "") }else if self?.oilQulity == 50 { self?.delegate?.oil50(name: self?.name ?? "") }else{ } }).disposed(by: disposeBag) } }
2.首先我们继承 DelegateProxy
创建一个关于上述类代理委托,同时它还要遵守 DelegateProxyType
和 CarOilProtocol协议。
// // CarCarOilProtocol.swift // Pod11 // // Created by dzq_mac on 2020/1/13. // Copyright © 2020 dzq_mac. All rights reserved. // import UIKit import RxSwift import RxCocoa import CoreLocation extension CarCar :HasDelegate{ public typealias Delegate = CarOilProtocol } public class RxCarCarOilProtocolProxy: DelegateProxy<CarCar,CarOilProtocol>,DelegateProxyType,CarOilProtocol { public init(car:CarCar) { super.init(parentObject: car, delegateProxy: RxCarCarOilProtocolProxy.self) } public static func registerKnownImplementations() { self.register { RxCarCarOilProtocolProxy(car: $0)} } internal lazy var oil80Subject = PublishSubject<String>() internal lazy var oil50Subject = PublishSubject<String>() public func oil80(name: String) -> String { let nn = _forwardToDelegate?.oil80(name: name)//原来的代理 oil80Subject.onNext(name) return nn ?? name } public func oil50(name: String) -> String { let mm = _forwardToDelegate?.oil50(name: name) oil50Subject.onNext(name) return mm ?? name } deinit { self.oil80Subject.on(.completed) self.oil50Subject.on(.completed) } }
3.接着我们对 Carcar 进行Rx
扩展,作用是将Carcar与前面创建的代理委托关联起来,将相关的 delegate
方法转为可观察序列。
// // CarCar+rx.swift // Pod11 // // Created by dzq_mac on 2020/1/13. // Copyright © 2020 dzq_mac. All rights reserved. // import UIKit import RxSwift import RxCocoa extension Reactive where Base:CarCar{ public var delegate:DelegateProxy<CarCar,CarOilProtocol>{ return RxCarCarOilProtocolProxy.proxy(for: base) } public var dao80:Observable<String>{ return RxCarCarOilProtocolProxy.proxy(for: base).oil80Subject.asObserver() // let source = delegate.methodInvoked(#selector(CarOilProtocol.oil80(name:))) // .map{ s in // // return try castOrThrow1(String.self,s[1]) // } // return source } public var dao50:Observable<String>{ return RxCarCarOilProtocolProxy.proxy(for: base).oil50Subject.asObserver() } public func setDelegate(_ delegate:CarOilProtocol) -> Disposable{ return RxCarCarOilProtocolProxy.installForwardDelegate(delegate, retainDelegate: false, onProxyForObject: self.base) } }
4在其他地方就可以像一般的RxSwift一样订阅这个序列了
var car : CarCar! override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.white car = CarCar(name: "beijing") car.delegate = self car.startRun() car.rx.dao80.asObservable().subscribe({ (str) in print("rx80--" + (str.element ?? "")) }).disposed(by: disposeBag) }
这样写,本来的代理的代理方法也会走,rx订阅的方法也会走,就实现了从单一代理到多代理的转化,RxSwift框架还是非常强大的,继续学习,有兴趣的可以一起交流啊!
原文地址:https://www.cnblogs.com/duzhaoquan/p/12195711.html