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框架還是非常強大的,繼續學習,有興趣的可以一起交流啊!




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM