iOS代理一对一秒变一对多--RxSwift delegateProxy使用
委托代理(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框架还是非常强大的,继续学习,有兴趣的可以一起交流啊!

浙公网安备 33010602011771号