如何让MapBox代理完全兼容RxSwift响应式编程?
实现MapBox AnnotationInteractionDelegate的RxSwift响应式封装
针对你遇到的MapBox代理无法适配RxSwift的问题,核心原因是MapBox新版的AnnotationInteractionDelegate方法是纯Swift实现,没有暴露给Objective-C,导致你之前用methodInvoked的方式无法捕获代理回调。以下是无需修改MapBox源码的正确实现方案:
核心实现步骤
1. 关联PointAnnotationManager与代理协议
先让PointAnnotationManager遵循HasDelegate协议,明确其代理类型:
import MapboxMaps import RxSwift import RxCocoa extension PointAnnotationManager: HasDelegate { public typealias Delegate = AnnotationInteractionDelegate }
2. 实现DelegateProxy并处理代理事件
自定义代理代理类,直接实现Swift代理方法,通过Subject转发事件,同时保留原代理的逻辑:
class RxAnnotationInteractionDelegateProxy: DelegateProxy<PointAnnotationManager, AnnotationInteractionDelegate>, DelegateProxyType, AnnotationInteractionDelegate { // 用于发送标注点击事件的Subject private let tappedAnnotationsSubject = PublishSubject<[PointAnnotation]>() var tappedAnnotationsObservable: Observable<[PointAnnotation]> { tappedAnnotationsSubject.asObservable() } weak private(set) var annotationManager: PointAnnotationManager? init(annotationManager: PointAnnotationManager) { self.annotationManager = annotationManager super.init(parentObject: annotationManager, delegateProxy: RxAnnotationInteractionDelegateProxy.self) } static func registerKnownImplementations() { register { RxAnnotationInteractionDelegateProxy(annotationManager: $0) } } // 实现代理方法,同时转发给原代理 func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) { // 保留原代理的回调逻辑(如果存在) forwardToDelegate()?.annotationManager(manager, didDetectTappedAnnotations: annotations) // 转换为PointAnnotation并发送Rx事件 let pointAnnotations = annotations.compactMap { $0 as? PointAnnotation } tappedAnnotationsSubject.onNext(pointAnnotations) } deinit { tappedAnnotationsSubject.onCompleted() } }
3. 扩展Reactive接口,提供可订阅的事件
给PointAnnotationManager的Rx扩展添加可直接使用的事件序列:
extension Reactive where Base: PointAnnotationManager { var delegate: RxAnnotationInteractionDelegateProxy { return RxAnnotationInteractionDelegateProxy.proxy(for: base) } var didDetectTappedAnnotations: ControlEvent<[PointAnnotation]> { let source = delegate.tappedAnnotationsObservable .catch { _ in Observable.empty() } // 可选:处理异常,避免序列中断 return ControlEvent(events: source) } }
使用方式
现在你可以像原生Rx控件一样订阅标注点击事件:
annotationManager.rx.didDetectTappedAnnotations .subscribe(onNext: { tappedAnnotations in // 处理点击的标注 print("点击了\(tappedAnnotations.count)个标注") }) .disposed(by: disposeBag)
解决你之前的问题点
- 无需修改MapBox源码:直接实现Swift代理方法,不依赖Objective-C runtime的消息转发
- 消除警告:通过
forwardToDelegate()调用原代理方法,既保留原有逻辑,又避免了"已实现代理方法"的警告 - 参数正确处理:直接从代理方法获取annotations数组,无需通过
methodInvoked的参数数组索引,避免类型转换错误
内容的提问来源于stack exchange,提问作者13thApostle
相关产品推荐
相关产品推荐

