I need to find the way to make MapBox delegates fully reactive, just like some many native ones. I managed to make MapBox annotations bindable by subscribing PointAnnotationManager to ReactiveCompatible protocol:
extension PointAnnotationManager: ReactiveCompatible {}
This gave me the possibility to bind to the annotations array:
viewModel.pointAnnotations
.drive(annotationManager.rx.annotations)
.disposed(by: disposeBag)
Now I am completely stuck with making MapBox delegates Reactive compatible. I need to have access to certain methods such as didSelectAnnotation etc.
I am new to both RxSwift and MapBox frameworks, I spent three days looking for a solution on the Internet in order not to bother the community in vain, but I wasn't able to find anything. So I've tried taking standard "ready to use" extensions as an example to extend my PointAnnotationManager:
extension PointAnnotationManager: HasDelegate {
public typealias Delegate = AnnotationInteractionDelegate
}
extension DelegateProxyType where ParentObject: HasDelegate, Self.Delegate == ParentObject.Delegate {
public static func currentDelegate(for object: ParentObject) -> Delegate? {
return object.delegate
}
public static func setCurrentDelegate(_ delegate: Delegate?, to object: ParentObject) {
object.delegate = delegate
}
}
class RXAnnotationInteractionDelegateProxy: DelegateProxy<PointAnnotationManager, AnnotationInteractionDelegate>, DelegateProxyType, AnnotationInteractionDelegate {
func annotationManager(_ manager: MapboxMaps.AnnotationManager, didDetectTappedAnnotations annotations: [MapboxMaps.Annotation]) {
}
public weak private(set) var annotationManager: PointAnnotationManager?
public init(annotationManager: ParentObject) {
self.annotationManager = annotationManager
super.init(parentObject: annotationManager, delegateProxy: RXAnnotationInteractionDelegateProxy.self)
}
static func registerKnownImplementations() {
self.register { RXAnnotationInteractionDelegateProxy.init(annotationManager: $0) }
}
}
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
}
extension Reactive where Base: PointAnnotationManager {
public var delegate: DelegateProxy<PointAnnotationManager, AnnotationInteractionDelegate> {
return RXAnnotationInteractionDelegateProxy.proxy(for: base)
}
public var didSelectAnnotation: ControlEvent<PointAnnotation> {
let source = delegate
.methodInvoked(#selector(AnnotationInteractionDelegate.annotationManager(_:didDetectTappedAnnotations:)))
.map { a in
return try castOrThrow(PointAnnotation.self, a[0])
}
return ControlEvent(events: source)
}
}
This implementation above didn't give me any results, moreover I had to edit some MapBox package files to make method annotationManager(_:didDetectTappedAnnotations:) exposable to objc, and this isn't good i suppose to put your hands on the code of the package.
However in the console i get the warning "Delegate proxy is already implementing annotationManager:didDetectTappedAnnotations:
, a more performant way of registering might exist." that gives me hope to find this "more performant way of registering".
I've also tried to downgrade MapBox version in order to get good old MGLMapViewDelegate, that can be easily reactively extended (if I am not mistaken)
Now I am not able to do anything with the code, nor to continue the project because I have a manic desire to get rid of the delegates and make the project fully reactive.