-
DelegateProxy
- DelegateProxy 是代理委托蹋偏,我們可以將它看作是代理的代理
- DelegateProxy 的作用是做為一個(gè)中間代理,他會(huì)先把系統(tǒng)的 delegate 對象保存一份威始,然后攔截 delegate 的方法像街。也就是說在每次觸發(fā) delegate 方法之前晋渺,會(huì)先調(diào)用 DelegateProxy 這邊對應(yīng)的方法木西,我們可以在這里發(fā)射序列給多個(gè)訂閱者
-
以獲取地理定位信息為例
-
創(chuàng)建RxCLLocationManagerDelegateProxy.swift
import CoreLocation import RxSwift import RxCocoa // 必須實(shí)現(xiàn) extension CLLocationManager: HasDelegate { public typealias Delegate = CLLocationManagerDelegate } // 必須遵守DelegateProxy和DelegateProxyType俭厚,其中DelegateProxy需要遵守對應(yīng)的類和對應(yīng)的代理,用<>,尖括號中宏逗號(,)隔開 public class RxCLLocationManagerDelegateProxy // 注意寫法 : DelegateProxy<CLLocationManager, CLLocationManagerDelegate> , DelegateProxyType , CLLocationManagerDelegate { // 必須實(shí)現(xiàn) public init(locationManager: CLLocationManager) { super.init(parentObject: locationManager, delegateProxy: RxCLLocationManagerDelegateProxy.self) } // 必須實(shí)現(xiàn) public static func registerKnownImplementations() { self.register { RxCLLocationManagerDelegateProxy(locationManager: $0) } } /*****************根據(jù)具體代理具體實(shí)現(xiàn)******************/ internal lazy var didUpdateLocationsSubject = PublishSubject<[CLLocation]>() internal lazy var didFailWithErrorSubject = PublishSubject<Error>() public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { _forwardToDelegate?.locationManager?(manager, didUpdateLocations: locations) didUpdateLocationsSubject.onNext(locations) } public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { _forwardToDelegate?.locationManager?(manager, didFailWithError: error) didFailWithErrorSubject.onNext(error) } /*****************根據(jù)具體代理具體實(shí)現(xiàn)******************/ // 必須實(shí)現(xiàn)扛门,把創(chuàng)建的序列結(jié)束掉 deinit { self.didUpdateLocationsSubject.on(.completed) self.didFailWithErrorSubject.on(.completed) } }
-
創(chuàng)建CLLocationManager+Rx.swift
import CoreLocation import RxSwift import RxCocoa extension Reactive where Base: CLLocationManager { /** Reactive wrapper for `delegate`. For more information take a look at `DelegateProxyType` protocol documentation. */ // 必須實(shí)現(xiàn) public var delegate: DelegateProxy<CLLocationManager, CLLocationManagerDelegate> { return RxCLLocationManagerDelegateProxy.proxy(for: base) } // 以下都是根據(jù)具體代理具體實(shí)現(xiàn) // MARK: Responding to Location Events /** Reactive wrapper for `delegate` message. */ public var didUpdateLocations: Observable<[CLLocation]> { return RxCLLocationManagerDelegateProxy.proxy(for: base) .didUpdateLocationsSubject.asObservable() } /** Reactive wrapper for `delegate` message. */ public var didFailWithError: Observable<Error> { return RxCLLocationManagerDelegateProxy.proxy(for: base) .didFailWithErrorSubject.asObservable() } #if os(iOS) || os(macOS) /** Reactive wrapper for `delegate` message. */ public var didFinishDeferredUpdatesWithError: Observable<Error?> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didFinishDeferredUpdatesWithError:))) .map { a in return try castOptionalOrThrow(Error.self, a[1]) } } #endif #if os(iOS) // MARK: Pausing Location Updates /** Reactive wrapper for `delegate` message. */ public var didPauseLocationUpdates: Observable<Void> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManagerDidPauseLocationUpdates(_:))) .map { _ in return () } } /** Reactive wrapper for `delegate` message. */ public var didResumeLocationUpdates: Observable<Void> { return delegate.methodInvoked( #selector(CLLocationManagerDelegate .locationManagerDidResumeLocationUpdates(_:))) .map { _ in return () } } // MARK: Responding to Heading Events /** Reactive wrapper for `delegate` message. */ public var didUpdateHeading: Observable<CLHeading> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didUpdateHeading:))) .map { a in return try castOrThrow(CLHeading.self, a[1]) } } // MARK: Responding to Region Events /** Reactive wrapper for `delegate` message. */ public var didEnterRegion: Observable<CLRegion> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didEnterRegion:))) .map { a in return try castOrThrow(CLRegion.self, a[1]) } } /** Reactive wrapper for `delegate` message. */ public var didExitRegion: Observable<CLRegion> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didExitRegion:))) .map { a in return try castOrThrow(CLRegion.self, a[1]) } } #endif #if os(iOS) || os(macOS) /** Reactive wrapper for `delegate` message. */ @available(OSX 10.10, *) public var didDetermineStateForRegion: Observable<(state: CLRegionState, region: CLRegion)> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didDetermineState:for:))) .map { a in let stateNumber = try castOrThrow(NSNumber.self, a[1]) let state = CLRegionState(rawValue: stateNumber.intValue) ?? CLRegionState.unknown let region = try castOrThrow(CLRegion.self, a[2]) return (state: state, region: region) } } /** Reactive wrapper for `delegate` message. */ public var monitoringDidFailForRegionWithError: Observable<(region: CLRegion?, error: Error)> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:monitoringDidFailFor:withError:))) .map { a in let region = try castOptionalOrThrow(CLRegion.self, a[1]) let error = try castOrThrow(Error.self, a[2]) return (region: region, error: error) } } /** Reactive wrapper for `delegate` message. */ public var didStartMonitoringForRegion: Observable<CLRegion> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didStartMonitoringFor:))) .map { a in return try castOrThrow(CLRegion.self, a[1]) } } #endif #if os(iOS) // MARK: Responding to Ranging Events /** Reactive wrapper for `delegate` message. */ public var didRangeBeaconsInRegion: Observable<(beacons: [CLBeacon], region: CLBeaconRegion)> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didRangeBeacons:in:))) .map { a in let beacons = try castOrThrow([CLBeacon].self, a[1]) let region = try castOrThrow(CLBeaconRegion.self, a[2]) return (beacons: beacons, region: region) } } /** Reactive wrapper for `delegate` message. */ public var rangingBeaconsDidFailForRegionWithError: Observable<(region: CLBeaconRegion, error: Error)> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:rangingBeaconsDidFailFor:withError:))) .map { a in let region = try castOrThrow(CLBeaconRegion.self, a[1]) let error = try castOrThrow(Error.self, a[2]) return (region: region, error: error) } } // MARK: Responding to Visit Events /** Reactive wrapper for `delegate` message. */ @available(iOS 8.0, *) public var didVisit: Observable<CLVisit> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didVisit:))) .map { a in return try castOrThrow(CLVisit.self, a[1]) } } #endif // MARK: Responding to Authorization Changes /** Reactive wrapper for `delegate` message. */ public var didChangeAuthorizationStatus: Observable<CLAuthorizationStatus> { return delegate.methodInvoked(#selector(CLLocationManagerDelegate .locationManager(_:didChangeAuthorization:))) .map { a in let number = try castOrThrow(NSNumber.self, a[1]) return CLAuthorizationStatus(rawValue: Int32(number.intValue)) ?? .notDetermined } } } /// 自定義的類型裝換方法 fileprivate 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 } /// 自定義的可選類型裝換方法 fileprivate func castOptionalOrThrow<T>(_ resultType: T.Type, _ object: Any) throws -> T? { if NSNull().isEqual(object) { return nil } guard let returnValue = object as? T else { throw RxCocoaError.castingError(object: object, targetType: resultType) } return returnValue }
-
參考文章:Swift - RxSwift的使用詳解58(DelegateProxy樣例1:獲取地理定位信息 )
Swift - RxSwift的使用詳解59(DelegateProxy樣例2:圖片選擇功能 )
Swift - RxSwift的使用詳解60(DelegateProxy樣例3:應(yīng)用生命周期的狀態(tài)變化)