You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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)

解决你之前的问题点

  1. 无需修改MapBox源码:直接实现Swift代理方法,不依赖Objective-C runtime的消息转发
  2. 消除警告:通过forwardToDelegate()调用原代理方法,既保留原有逻辑,又避免了"已实现代理方法"的警告
  3. 参数正确处理:直接从代理方法获取annotations数组,无需通过methodInvoked的参数数组索引,避免类型转换错误

内容的提问来源于stack exchange,提问作者13thApostle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 06:10:25