RxSwift 給代理添加Rx擴(kuò)展

在RxCocoa里面封裝了大量系統(tǒng)UI組件的擴(kuò)展霹抛,我們可以仿照RxCocoa里面的封裝方式搓逾,給自己的代理也添加Rx的擴(kuò)展。

大概原理就是通過DelegateProxy把delegate的方法調(diào)用轉(zhuǎn)換為一個observable sequence杯拐。

這里我們用CLLocationManager代理的封裝作為例子霞篡。

1.創(chuàng)建一個RXCLLocationManagerDelegateProxy類
open class RXCLLocationManagerDelegateProxy:
    DelegateProxy<CLLocationManager, CLLocationManagerDelegate>,
    DelegateProxyType,
    CLLocationManagerDelegate  {
    
    public weak private(set) var locationManager: CLLocationManager?
    
    public init(locationManager: ParentObject) {
        self.locationManager = locationManager
        super.init(parentObject: locationManager, delegateProxy: RXCLLocationManagerDelegateProxy.self)
    }
    
    public static func registerKnownImplementations() {
        self.register { RXCLLocationManagerDelegateProxy(locationManager: $0) }
    }
    
    public class func currentDelegate(for object: ParentObject) -> CLLocationManagerDelegate? {
        return object.delegate
    }
    
    public class func setCurrentDelegate(_ delegate: CLLocationManagerDelegate?, to object: ParentObject) {
        object.delegate = delegate
    }
}
2.讓CLLocationManager遵循HasDelegate
extension CLLocationManager: HasDelegate {
    public typealias Delegate = CLLocationManagerDelegate
}
3.給CLLocationManager創(chuàng)建Reactive擴(kuò)展
extension Reactive where Base: CLLocationManager {
    
    public var delegate: RXCLLocationManagerDelegateProxy {
        return RXCLLocationManagerDelegateProxy.proxy(for: base)
    }
    
    public var didUpdateLocations: ControlEvent<(manager: CLLocationManager, locations: [CLLocation])> {
        let sel = #selector(CLLocationManagerDelegate.locationManager(_:didUpdateLocations:))
    
        let source = delegate.methodInvoked(sel).map{ (args) -> (manager: CLLocationManager, locations: [CLLocation]) in
            let manager = try castOrThrow(CLLocationManager.self, args[0])
            let locations = try castOrThrow(Array<CLLocation>.self, args[1])
            return (manager, locations)
        }
        return ControlEvent(events: source)
    }
    
    public var didError: ControlEvent<(manager: CLLocationManager, error: Error)> {
        let didFailWithErrorSel = #selector(CLLocationManagerDelegate.locationManager(_:didFailWithError:))
        let didFinishDeferredUpdatesWithErrorSel = #selector(CLLocationManagerDelegate.locationManager(_:didFinishDeferredUpdatesWithError:))
        let generalError = delegate
            .methodInvoked(didFailWithErrorSel)
            .map(clErrorEvent)
        let updatesError = delegate
            .methodInvoked(didFinishDeferredUpdatesWithErrorSel)
            .map(clErrorEvent)
        let source = Observable.of(generalError, updatesError).merge()
        return ControlEvent(events: source)
    }
    
    private func clErrorEvent(_ args: [Any]) throws -> (manager: CLLocationManager, error: Error) {
        let manager = try castOrThrow(CLLocationManager.self, args[0])
        let error = try castOrThrow(Error.self, args[1])
        return (manager, error)
    }
    
    public var didErrorRangingBeacons: ControlEvent<(manager: CLLocationManager, region: CLBeaconRegion, error: Error)> {
        let rangingBeaconsDidFailForRegionSel = #selector(CLLocationManagerDelegate.locationManager(_:rangingBeaconsDidFailFor:withError:))
        let source = delegate
            .methodInvoked(rangingBeaconsDidFailForRegionSel)
            .map { (args) -> (manager: CLLocationManager, region: CLBeaconRegion, error: Error) in
                let manager = try castOrThrow(CLLocationManager.self, args[0])
                let beaconRegion = try castOrThrow(CLBeaconRegion.self, args[1])
                let error = try castOrThrow(Error.self, args[2])
                return (manager, beaconRegion, error)
            }
        return ControlEvent(events: source)
    }
    
}
注意

RxCocoa的 castOrThrow 這個方法沒有加public修飾,所以我們是沒法調(diào)用端逼,我們需要Copy出來.

func castOrThrow<T>(_ resultType: T.Type, _ object: Any) throws -> T {
    guard let returnValue = object as? T else {
        throw RxCocoaError.castingError(object: object, targetType: resultType)
    }
    return returnValue
}

然后我們就可以使用了
llocationManager.rx
    .didUpdateLocations
    .subscribe(onNext: { (_, locations) in
        print(locations)
    })
    .disposed(by: disposeBag)

locationManager.rx
    .didError
    .subscribe(onNext: { (_, error) in
        print(error)
    })
    .disposed(by: disposeBag)

locationManager.rx
    .didErrorRangingBeacons
    .subscribe(onNext: { (_, beacons, _) in
        print(beacons)
    })
    .disposed(by: disposeBag)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朗兵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子顶滩,更是在濱河造成了極大的恐慌余掖,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件礁鲁,死亡現(xiàn)場離奇詭異浊吏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)救氯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門找田,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人着憨,你說我怎么就攤上這事墩衙。” “怎么了甲抖?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵漆改,是天一觀的道長。 經(jīng)常有香客問我准谚,道長挫剑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任柱衔,我火速辦了婚禮樊破,結(jié)果婚禮上愉棱,老公的妹妹穿的比我還像新娘。我一直安慰自己哲戚,他們只是感情好奔滑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著顺少,像睡著了一般朋其。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脆炎,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天梅猿,我揣著相機(jī)與錄音,去河邊找鬼秒裕。 笑死粒没,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的簇爆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼爽撒,長吁一口氣:“原來是場噩夢啊……” “哼入蛆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硕勿,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤哨毁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后源武,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扼褪,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年粱栖,在試婚紗的時候發(fā)現(xiàn)自己被綠了话浇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡闹究,死狀恐怖幔崖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渣淤,我是刑警寧澤赏寇,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站价认,受9級特大地震影響嗅定,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜用踩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一渠退、第九天 我趴在偏房一處隱蔽的房頂上張望忙迁。 院中可真熱鬧,春花似錦智什、人聲如沸动漾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旱眯。三九已至,卻和暖如春证九,著一層夾襖步出監(jiān)牢的瞬間删豺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工愧怜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呀页,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓拥坛,卻偏偏與公主長得像蓬蝶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子猜惋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容