iOS代理一对一秒变一对多--RxSwift delegateProxy使用

Posted 不停奔跑的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS代理一对一秒变一对多--RxSwift delegateProxy使用相关的知识,希望对你有一定的参考价值。

     委托代理(delegateios 开发中十分常见。不管是使用系统自带的库,还是一些第三方组件时,我们总能看到 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框架还是非常强大的,继续学习,有兴趣的可以一起交流啊!



以上是关于iOS代理一对一秒变一对多--RxSwift delegateProxy使用的主要内容,如果未能解决你的问题,请参考以下文章

iOS:“@count == 0”的 NSPredicate 用于一对一和一对多关系

mybatis的动态sql编写以及一对一关系查询和一对多的查询

laravel 一对多在一侧返回 null

一对多聊天室

IOS:通过一对多关系获取核心数据

iOS核心数据一对多关系NSSET