From 9a9bc352093dfbe0d46f8245d1451a16fed6cdfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Fazekas?= Date: Tue, 7 May 2024 15:50:18 +0200 Subject: [PATCH] ios: fix unavailable mapView on initialization (#3477) --- ios/RNMBX/RNMBXMapView.swift | 34 ++++++++--- ios/RNMBX/RNMBXMapViewManager.swift | 94 +++++++++++------------------ 2 files changed, 60 insertions(+), 68 deletions(-) diff --git a/ios/RNMBX/RNMBXMapView.swift b/ios/RNMBX/RNMBXMapView.swift index f9b250560..bdadab732 100644 --- a/ios/RNMBX/RNMBXMapView.swift +++ b/ios/RNMBX/RNMBXMapView.swift @@ -171,7 +171,7 @@ open class RNMBXMapView: UIView { }() var _mapView: MapView! = nil - func createMapView() { + func createMapView() -> MapView { if let mapViewImpl = mapViewImpl, let mapViewInstance = createAndAddMapViewImpl(mapViewImpl, self) { _mapView = mapViewInstance } else { @@ -192,6 +192,7 @@ open class RNMBXMapView: UIView { _mapView.gestures.delegate = self setupEvents() afterMapViewAdded() + return _mapView } func createAndAddMapViewImpl(_ impl: String, _ view: RNMBXMapView) -> MapView? { @@ -203,17 +204,20 @@ open class RNMBXMapView: UIView { } } + @available(*, deprecated, renamed: "withMapView", message: "mapView can be nil if the map initialization has not finished, use withMapView instead") public var mapView : MapView! { get { return _mapView } } + + @available(*, deprecated, renamed: "withMapboxMap", message: "mapboxMap can be nil if the map initialization has not finished, use withMapboxMap instead") var mapboxMap: MapboxMap! { - get { _mapView.mapboxMap } + get { _mapView?.mapboxMap } } @objc public func addToMap(_ subview: UIView) { - withMapView { + withMapView { mapView in if let mapComponent = subview as? RNMBXMapComponent { - let style = self.mapView.mapboxMap.style + let style = mapView.mapboxMap.style var addToMap = false if mapComponent.waitForStyleLoad() { if (self.styleLoaded) { @@ -303,7 +307,7 @@ open class RNMBXMapView: UIView { // MARK: - React Native properties let changes : PropertyChanges = PropertyChanges() - var mapViewWaiters : [()->Void] = [] + var mapViewWaiters : [(_: MapView)->Void] = [] enum Property : String { case projection @@ -363,14 +367,24 @@ open class RNMBXMapView: UIView { changes.add(name: property.rawValue, update: property.apply) } - func withMapView(callback: @escaping () -> Void) { - if _mapView != nil { - callback() + func withMapView(callback: @escaping (_: MapView) -> Void) { + if let mapView = _mapView { + callback(mapView) } else { mapViewWaiters.append(callback) } } + func withMapboxMap(callback: @escaping (_: MapboxMap) -> Void) { + if let mapboxMap = _mapView?.mapboxMap { + callback(mapboxMap) + } else { + mapViewWaiters.append { mapView in + callback(mapView.mapboxMap) + } + } + } + var projection: StyleProjection? @objc public func setReactProjection(_ value: String?) { @@ -698,9 +712,9 @@ open class RNMBXMapView: UIView { @objc override public func didSetProps(_ props: [String]) { if (_mapView == nil) { - createMapView() + let view = createMapView() - mapViewWaiters.forEach { $0() } + mapViewWaiters.forEach { $0(view) } mapViewWaiters.removeAll() } changes.apply(self) diff --git a/ios/RNMBX/RNMBXMapViewManager.swift b/ios/RNMBX/RNMBXMapViewManager.swift index 2224fa9ad..53834dfdb 100644 --- a/ios/RNMBX/RNMBXMapViewManager.swift +++ b/ios/RNMBX/RNMBXMapViewManager.swift @@ -23,25 +23,6 @@ open class RNMBXMapViewManager: RCTViewManager { } } -// MARK: helpers - -extension RNMBXMapViewManager { - static func withMapboxMap( - _ view: RNMBXMapView, - name: String, - rejecter: @escaping RCTPromiseRejectBlock, - fn: @escaping (_: MapboxMap) -> Void) -> Void - { - guard let mapboxMap = view.mapboxMap else { - RNMBXLogError("MapboxMap is not yet available"); - rejecter(name, "Map not loaded yet", nil) - return; - } - - fn(mapboxMap) - } -} - // MARK: - react methods extension RNMBXMapViewManager { @@ -76,12 +57,12 @@ extension RNMBXMapViewManager { } @objc public static func getCenter(_ view: RNMBXMapView, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(view, name: "getCenter", rejecter:rejecter) { map in - resolver(["center": [ - map.cameraState.center.longitude, - map.cameraState.center.latitude - ]]) - } + view.withMapboxMap { map in + resolver(["center": [ + map.cameraState.center.longitude, + map.cameraState.center.latitude + ]]) + } } @objc public static func getCoordinateFromView( @@ -89,10 +70,10 @@ extension RNMBXMapViewManager { atPoint point: CGPoint, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(view, name: "getCoordinateFromView", rejecter:rejecter) { map in - let coordinates = map.coordinate(for: point) - resolver(["coordinateFromView": [coordinates.longitude, coordinates.latitude]]) - } + view.withMapboxMap { map in + let coordinates = map.coordinate(for: point) + resolver(["coordinateFromView": [coordinates.longitude, coordinates.latitude]]) + } } @@ -101,12 +82,11 @@ extension RNMBXMapViewManager { atCoordinate coordinate: [NSNumber], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(view, name: "getPointInView", rejecter:rejecter) { map in - let coordinate = CLLocationCoordinate2DMake(coordinate[1].doubleValue, coordinate[0].doubleValue) - let point = map.point(for: coordinate) - resolver(["pointInView": [(point.x), (point.y)]]) - } - + view.withMapboxMap { map in + let coordinate = CLLocationCoordinate2DMake(coordinate[1].doubleValue, coordinate[0].doubleValue) + let point = map.point(for: coordinate) + resolver(["pointInView": [(point.x), (point.y)]]) + } } @objc public static func setHandledMapChangedEvents( @@ -124,10 +104,9 @@ extension RNMBXMapViewManager { _ view: RNMBXMapView, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(view, name: "getZoom", rejecter:rejecter) { map in - resolver(["zoom": map.cameraState.zoom]) - } - + view.withMapboxMap { map in + resolver(["zoom": map.cameraState.zoom]) + } } @objc public static func getVisibleBounds( @@ -148,27 +127,26 @@ extension RNMBXMapViewManager { withLayerIDs layerIDs: [String]?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapboxMap(view, name: "queryRenderedFeaturesAtPoint", rejecter:rejecter) { map in - let point = CGPoint(x: CGFloat(point[0].floatValue), y: CGFloat(point[1].floatValue)) - - logged("queryRenderedFeaturesAtPoint.option", rejecter: rejecter) { - let options = try RenderedQueryOptions(layerIds: (layerIDs ?? []).isEmpty ? nil : layerIDs, filter: filter?.asExpression()) - - map.queryRenderedFeatures(with: point, options: options) { result in - switch result { - case .success(let features): - resolver([ - "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in - logged("queryRenderedFeaturesAtPoint.feature.toJSON") { try queriedFeature.feature.toJSON() } - }] - ]) - case .failure(let error): - rejecter("queryRenderedFeaturesAtPoint","failed to query features", error) - } + view.withMapboxMap { map in + let point = CGPoint(x: CGFloat(point[0].floatValue), y: CGFloat(point[1].floatValue)) + + logged("queryRenderedFeaturesAtPoint.option", rejecter: rejecter) { + let options = try RenderedQueryOptions(layerIds: (layerIDs ?? []).isEmpty ? nil : layerIDs, filter: filter?.asExpression()) + + map.queryRenderedFeatures(with: point, options: options) { result in + switch result { + case .success(let features): + resolver([ + "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in + logged("queryRenderedFeaturesAtPoint.feature.toJSON") { try queriedFeature.feature.toJSON() } + }] + ]) + case .failure(let error): + rejecter("queryRenderedFeaturesAtPoint","failed to query features", error) } } - } - + } + } } @objc public static func queryRenderedFeaturesInRect(