美文网首页
代理转换为可观察序列(DelegateProxy)

代理转换为可观察序列(DelegateProxy)

作者: FallPine | 来源:发表于2018-09-14 16:02 被阅读39次
  • 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:应用生命周期的状态变化)

相关文章

  • 代理转换为可观察序列(DelegateProxy)

    DelegateProxyDelegateProxy 是代理委托,我们可以将它看作是代理的代理DelegatePr...

  • Java序列化和反序列化

    序列化:把对象转换为字节序列的过程。 反序列化:把字节对象恢复为对象的过程。 用途:将对象转换为字节序列变成了可存...

  • 算术和集合操作

    对可观察到的整个序列进行操作的操作符。 toArray 将可观察序列转换为数组,将该数组作为一个新的单元素可观察序...

  • Java基础知识系列—序列化

    序列化是将对象的状态转换为字节流;反序列化恰恰相反。换言之,序列化是将Java对象转换为字节的静态流(序列,然后可...

  • python基础之序列化和反序列化

    一、定义 1、序列化:就是把不可传输的对象转换为可存储或可传输的过程 2、反序列化:就是把在磁盘,等介质中的数据转...

  • Json XML序列化和反序列化

    1.json序列化和反序列化 序列化是将对象状态转换为可保持或传输的格式的过程; 反序列化,它将流转换为对象; 1...

  • 09.RxSwift 高阶函数(三)

    4. 集合控制操作符 4.1 toArray 将一个可观察序列转换为一个数组,将该数组作为一个新的单元素可观察序列...

  • RxSwift 小记-Mathematical and Aggr

    (*useful)标记:目前觉得有用的函数//FIXME 标记:待补充 toArray: 将可观察序列转换为数组...

  • java序列化学习笔记

    概念 序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。 这两个过程结...

  • Android开发篇之对象序列化

    Android开发篇之对象序列化 什么是序列化?序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是...

网友评论

      本文标题:代理转换为可观察序列(DelegateProxy)

      本文链接:https://www.haomeiwen.com/subject/nvvogftx.html