-
DelegateProxy
- DelegateProxy 是代理委托,我们可以将它看作是代理的代理
- DelegateProxy 的作用是做为一个中间代理,他会先把系统的 delegate 对象保存一份,然后拦截 delegate 的方法。也就是说在每次触发 delegate 方法之前,会先调用 DelegateProxy 这边对应的方法,我们可以在这里发射序列给多个订阅者
-
以获取地理定位信息为例
-
创建RxCLLocationManagerDelegateProxy.swift
import CoreLocation import RxSwift import RxCocoa // 必须实现 extension CLLocationManager: HasDelegate { public typealias Delegate = CLLocationManagerDelegate } // 必须遵守DelegateProxy和DelegateProxyType,其中DelegateProxy需要遵守对应的类和对应的代理,用<>,尖括号中宏逗号(,)隔开 public class RxCLLocationManagerDelegateProxy // 注意写法 : DelegateProxy<CLLocationManager, CLLocationManagerDelegate> , DelegateProxyType , CLLocationManagerDelegate { // 必须实现 public init(locationManager: CLLocationManager) { super.init(parentObject: locationManager, delegateProxy: RxCLLocationManagerDelegateProxy.self) } // 必须实现 public static func registerKnownImplementations() { self.register { RxCLLocationManagerDelegateProxy(locationManager: $0) } } /*****************根据具体代理具体实现******************/ 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) } /*****************根据具体代理具体实现******************/ // 必须实现,把创建的序列结束掉 deinit { self.didUpdateLocationsSubject.on(.completed) self.didFailWithErrorSubject.on(.completed) } }
-
创建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. */ // 必须实现 public var delegate: DelegateProxy<CLLocationManager, CLLocationManagerDelegate> { return RxCLLocationManagerDelegateProxy.proxy(for: base) } // 以下都是根据具体代理具体实现 // 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:应用生命周期的状态变化)