summaryrefslogtreecommitdiff
path: root/platform/ios/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ios/src')
-rw-r--r--platform/ios/src/MGLMapView.h34
-rw-r--r--platform/ios/src/MGLMapView.mm329
-rw-r--r--platform/ios/src/MGLMapView_Private.h5
3 files changed, 267 insertions, 101 deletions
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 0f8de86555..fd433fe1b3 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -636,11 +636,14 @@ MGL_EXPORT IB_DESIGNABLE
Changing the center coordinate centers the map on the new coordinate without
changing the current zoom level.
-
+
@param coordinate The new center coordinate for the map.
@param animated Specify `YES` if you want the map view to scroll to the new
location or `NO` if you want the map to display the new location
immediately.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`.
*/
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
@@ -653,6 +656,9 @@ MGL_EXPORT IB_DESIGNABLE
@param animated Specify `YES` if you want the map view to animate scrolling and
zooming to the new location or `NO` if you want the map to display the new
location immediately.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`.
*/
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated;
@@ -667,6 +673,9 @@ MGL_EXPORT IB_DESIGNABLE
@param animated Specify `YES` if you want the map view to animate scrolling,
zooming, and rotating to the new location or `NO` if you want the map to
display the new location immediately.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`.
*/
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated;
@@ -682,6 +691,9 @@ MGL_EXPORT IB_DESIGNABLE
zooming, and rotating to the new location or `NO` if you want the map to
display the new location immediately.
@param completion The block executed after the animation finishes.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`.
*/
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
@@ -1020,6 +1032,10 @@ MGL_EXPORT IB_DESIGNABLE
bounds with zoom level as high (close to the ground) as possible while still
including the entire coordinate bounds. The camera object uses the current
direction and pitch.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`; you may receive a `nil` return value
+ depending on the order of notification delivery.
*/
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds;
@@ -1034,6 +1050,10 @@ MGL_EXPORT IB_DESIGNABLE
with zoom level as high (close to the ground) as possible while still
including the entire coordinate bounds. The camera object uses the current
direction and pitch.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`; you may receive a `nil` return value
+ depending on the order of notification delivery.
*/
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets;
@@ -1050,6 +1070,10 @@ MGL_EXPORT IB_DESIGNABLE
with zoom level as high (close to the ground) as possible while still
including the entire coordinate bounds. The initial camera's pitch and
direction will be honored.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`; you may receive a `nil` return value
+ depending on the order of notification delivery.
*/
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets;
@@ -1065,6 +1089,10 @@ MGL_EXPORT IB_DESIGNABLE
@return A camera object centered on the shape's center with zoom level as high
(close to the ground) as possible while still including the entire shape. The
initial camera's pitch and direction will be honored.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`; you may receive a `nil` return value
+ depending on the order of notification delivery.
*/
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingShape:(MGLShape *)shape edgePadding:(UIEdgeInsets)insets;
@@ -1079,6 +1107,10 @@ MGL_EXPORT IB_DESIGNABLE
@return A camera object centered on the shape's center with zoom level as high
(close to the ground) as possible while still including the entire shape. The
camera object uses the current pitch.
+
+ @note The behavior of this method is undefined if called in response to
+ `UIApplicationWillTerminateNotification`; you may receive a `nil` return value
+ depending on the order of notification delivery.
*/
- (MGLMapCamera *)cameraThatFitsShape:(MGLShape *)shape direction:(CLLocationDirection)direction edgePadding:(UIEdgeInsets)insets;
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 05168ea819..8ab612663c 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -94,6 +94,7 @@ const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondMaxim
const MGLExceptionName MGLMissingLocationServicesUsageDescriptionException = @"MGLMissingLocationServicesUsageDescriptionException";
const MGLExceptionName MGLUserLocationAnnotationTypeException = @"MGLUserLocationAnnotationTypeException";
const MGLExceptionName MGLResourceNotFoundException = @"MGLResourceNotFoundException";
+const MGLExceptionName MGLUnderlyingMapUnavailableException = @"MGLUnderlyingMapUnavailableException";
/// Indicates the manner in which the map view is tracking the user location.
typedef NS_ENUM(NSUInteger, MGLUserTrackingState) {
@@ -249,6 +250,14 @@ public:
@property (nonatomic) CFTimeInterval frameTime;
@property (nonatomic) CFTimeInterval averageFrameTime;
+/// Residual properties (saved on app termination)
+@property (nonatomic) BOOL terminated;
+@property (nonatomic, copy) MGLMapCamera *residualCamera;
+@property (nonatomic) MGLMapDebugMaskOptions residualDebugMask;
+@property (nonatomic, copy) NSURL *residualStyleURL;
+
+- (mbgl::Map &)mbglMap;
+
@end
@implementation MGLMapView
@@ -372,7 +381,13 @@ public:
- (nonnull NSURL *)styleURL
{
- NSString *styleURLString = @(_mbglMap->getStyle().getURL().c_str()).mgl_stringOrNilIfEmpty;
+ if (!_mbglMap)
+ {
+ NSAssert(self.terminated, @"_mbglMap should only be unavailable during app termination");
+ return self.residualStyleURL;
+ }
+
+ NSString *styleURLString = @(self.mbglMap.getStyle().getURL().c_str()).mgl_stringOrNilIfEmpty;
MGLAssert(styleURLString || _isTargetingInterfaceBuilder, @"Invalid style URL string %@", styleURLString);
return styleURLString ? [NSURL URLWithString:styleURLString] : nil;
}
@@ -388,19 +403,24 @@ public:
MGLLogDebug(@"Setting styleURL: %@", styleURL);
styleURL = styleURL.mgl_URLByStandardizingScheme;
self.style = nil;
- _mbglMap->getStyle().loadURL([[styleURL absoluteString] UTF8String]);
+ self.mbglMap.getStyle().loadURL([[styleURL absoluteString] UTF8String]);
}
- (IBAction)reloadStyle:(__unused id)sender {
MGLLogInfo(@"Reloading style.");
NSURL *styleURL = self.styleURL;
- _mbglMap->getStyle().loadURL("");
+ self.mbglMap.getStyle().loadURL("");
self.styleURL = styleURL;
}
-- (mbgl::Map *)mbglMap
+- (mbgl::Map &)mbglMap
{
- return _mbglMap;
+ if (!_mbglMap)
+ {
+ [NSException raise:MGLUnderlyingMapUnavailableException
+ format:@"The underlying map is not available - this happens during app termination"];
+ }
+ return *_mbglMap;
}
- (mbgl::Renderer *)renderer
@@ -447,6 +467,8 @@ public:
auto renderer = std::make_unique<mbgl::Renderer>(*_mbglView, config.scaleFactor, *config.fileSource, *_mbglThreadPool, config.contextMode, config.cacheDir, config.localFontFamilyName);
BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
_rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, *_mbglView);
+
+ NSAssert(!_mbglMap, @"_mbglMap should be NULL");
_mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, config.scaleFactor, *[config fileSource], *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default, enableCrossSourceCollisions);
// start paused if in IB
@@ -686,6 +708,26 @@ public:
_isWaitingForRedundantReachableNotification = NO;
}
+
+- (void)destroyCoreObjects {
+ // Record the current state. Currently only saving a limited set of properties.
+ self.terminated = YES;
+ self.residualCamera = self.camera;
+ self.residualDebugMask = self.debugMask;
+ self.residualStyleURL = self.styleURL;
+
+ // Tear down C++ objects, insuring worker threads correctly terminate.
+ // Because of how _mbglMap is constructed, we need to destroy it first.
+ delete _mbglMap;
+ _mbglMap = nullptr;
+
+ delete _mbglView;
+ _mbglView = nullptr;
+
+ _rendererFrontend.reset();
+ _mbglThreadPool.reset();
+}
+
- (void)dealloc
{
MGLLogInfo(@"Deallocating MGLMapView.");
@@ -704,17 +746,7 @@ public:
[self validateDisplayLink];
- if (_mbglMap)
- {
- delete _mbglMap;
- _mbglMap = nullptr;
- }
-
- if (_mbglView)
- {
- delete _mbglView;
- _mbglView = nullptr;
- }
+ [self destroyCoreObjects];
if ([[EAGLContext currentContext] isEqual:_context])
{
@@ -1017,8 +1049,8 @@ public:
[self adjustContentInset];
- if (!_isTargetingInterfaceBuilder) {
- _mbglMap->setSize([self size]);
+ if (!_isTargetingInterfaceBuilder && _mbglMap) {
+ self.mbglMap.setSize([self size]);
}
if (self.compassView.alpha)
@@ -1176,6 +1208,8 @@ public:
self.dormant = YES;
[self.glView deleteDrawable];
}
+
+ [self destroyCoreObjects];
}
- (void)validateDisplayLink
@@ -1183,9 +1217,9 @@ public:
BOOL isVisible = self.superview && self.window;
if (isVisible && ! _displayLink)
{
- if (_mbglMap->getConstrainMode() == mbgl::ConstrainMode::None)
+ if (_mbglMap && self.mbglMap.getConstrainMode() == mbgl::ConstrainMode::None)
{
- _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly);
+ self.mbglMap.setConstrainMode(mbgl::ConstrainMode::HeightOnly);
}
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateFromDisplayLink)];
@@ -1385,7 +1419,7 @@ public:
return;
};
- _mbglMap->setGestureInProgress(false);
+ self.mbglMap.setGestureInProgress(false);
if (self.userTrackingState == MGLUserTrackingStateBegan)
{
[self setUserTrackingMode:MGLUserTrackingModeNone animated:NO];
@@ -1398,7 +1432,7 @@ public:
BOOL animated = NO;
[self cameraWillChangeAnimated:animated];
- _mbglMap->setGestureInProgress(true);
+ self.mbglMap.setGestureInProgress(true);
_changeDelimiterSuppressionDepth++;
}
@@ -1407,7 +1441,7 @@ public:
MGLAssert(_changeDelimiterSuppressionDepth >= 0,
@"Unbalanced change delimiter suppression/unsuppression");
if (_changeDelimiterSuppressionDepth == 0) {
- _mbglMap->setGestureInProgress(false);
+ self.mbglMap.setGestureInProgress(false);
}
if ( ! drift)
{
@@ -1463,7 +1497,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->moveBy({ delta.x, delta.y });
+ self.mbglMap.moveBy({ delta.x, delta.y });
[pan setTranslation:CGPointZero inView:pan.view];
}
@@ -1486,7 +1520,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->moveBy({ offset.x, offset.y }, MGLDurationFromTimeInterval(self.decelerationRate));
+ self.mbglMap.moveBy({ offset.x, offset.y }, MGLDurationFromTimeInterval(self.decelerationRate));
}
}
@@ -1521,7 +1555,7 @@ public:
{
[self trackGestureEvent:MMEEventGesturePinchStart forRecognizer:pinch];
- self.scale = powf(2, _mbglMap->getZoom());
+ self.scale = powf(2, self.mbglMap.getZoom());
[self notifyGestureDidBegin];
}
@@ -1536,7 +1570,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ self.mbglMap.setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
// The gesture recognizer only reports the gesture’s current center
// point, so use the previous center point to anchor the transition.
// If the number of touches has changed, the remembered center point is
@@ -1544,7 +1578,7 @@ public:
if (self.userTrackingMode == MGLUserTrackingModeNone && pinch.numberOfTouches == _previousPinchNumberOfTouches)
{
CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate;
- _mbglMap->setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate),
+ self.mbglMap.setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate),
mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
}
@@ -1576,7 +1610,7 @@ public:
newScale += scale / (velocity * duration) * 0.1;
}
- if (newScale <= 0 || log2(newScale) < _mbglMap->getMinZoom())
+ if (newScale <= 0 || log2(newScale) < self.mbglMap.getMinZoom())
{
velocity = 0;
}
@@ -1595,7 +1629,7 @@ public:
{
if (drift)
{
- _mbglMap->setZoom(zoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(duration));
+ self.mbglMap.setZoom(zoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(duration));
}
}
@@ -1622,7 +1656,7 @@ public:
{
[self trackGestureEvent:MMEEventGestureRotateStart forRecognizer:rotate];
- self.angle = MGLRadiansFromDegrees(_mbglMap->getBearing()) * -1;
+ self.angle = MGLRadiansFromDegrees(self.mbglMap.getBearing()) * -1;
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
@@ -1649,7 +1683,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ self.mbglMap.setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
[self cameraIsChanging];
@@ -1684,7 +1718,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(decelerationRate));
+ self.mbglMap.setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(decelerationRate));
[self notifyGestureDidEndWithDrift:YES];
@@ -1816,7 +1850,7 @@ public:
[self trackGestureEvent:MMEEventGestureDoubleTap forRecognizer:doubleTap];
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- _mbglMap->setZoom(newZoom, center, MGLDurationFromTimeInterval(MGLAnimationDuration));
+ self.mbglMap.setZoom(newZoom, center, MGLDurationFromTimeInterval(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -1837,7 +1871,7 @@ public:
if ( ! self.isZoomEnabled) return;
- if (_mbglMap->getZoom() == _mbglMap->getMinZoom()) return;
+ if (self.mbglMap.getZoom() == self.mbglMap.getMinZoom()) return;
[self cancelTransitions];
@@ -1856,7 +1890,7 @@ public:
[self trackGestureEvent:MMEEventGestureTwoFingerSingleTap forRecognizer:twoFingerTap];
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- _mbglMap->setZoom(newZoom, center, MGLDurationFromTimeInterval(MGLAnimationDuration));
+ self.mbglMap.setZoom(newZoom, center, MGLDurationFromTimeInterval(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -1879,7 +1913,7 @@ public:
{
[self trackGestureEvent:MMEEventGestureQuickZoom forRecognizer:quickZoom];
- self.scale = powf(2, _mbglMap->getZoom());
+ self.scale = powf(2, self.mbglMap.getZoom());
self.quickZoomStart = [quickZoom locationInView:quickZoom.view].y;
@@ -1889,9 +1923,9 @@ public:
{
CGFloat distance = [quickZoom locationInView:quickZoom.view].y - self.quickZoomStart;
- CGFloat newZoom = MAX(log2f(self.scale) + (distance / 75), _mbglMap->getMinZoom());
+ CGFloat newZoom = MAX(log2f(self.scale) + (distance / 75), self.mbglMap.getMinZoom());
- if (_mbglMap->getZoom() == newZoom) return;
+ if (self.mbglMap.getZoom() == newZoom) return;
CGPoint centerPoint = [self anchorPointForGesture:quickZoom];
@@ -1900,7 +1934,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ self.mbglMap.setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
[self cameraIsChanging];
@@ -1929,7 +1963,7 @@ public:
if (twoFingerDrag.state == UIGestureRecognizerStateBegan || twoFingerDrag.state == UIGestureRecognizerStateChanged)
{
CGFloat gestureDistance = CGPoint([twoFingerDrag translationInView:twoFingerDrag.view]).y;
- CGFloat currentPitch = _mbglMap->getPitch();
+ CGFloat currentPitch = self.mbglMap.getPitch();
CGFloat slowdown = 20.0;
CGFloat pitchNew = currentPitch - (gestureDistance / slowdown);
@@ -1941,7 +1975,7 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ self.mbglMap.setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
[self cameraIsChanging];
@@ -1971,11 +2005,11 @@ public:
{
mbgl::ScreenCoordinate anchor = mbgl::ScreenCoordinate { anchorPoint.x, anchorPoint.y };
mbgl::EdgeInsets padding = mbgl::EdgeInsets(anchor.y, anchor.x, self.size.height - anchor.y, self.size.width - anchor.x);
- mbgl::CameraOptions currentCameraOptions = _mbglMap->getCameraOptions(padding);
+ mbgl::CameraOptions currentCameraOptions = self.mbglMap.getCameraOptions(padding);
currentCameraOptions.zoom = mbgl::util::clamp(zoom, self.minimumZoomLevel, self.maximumZoomLevel);
currentCameraOptions.anchor = anchor;
- MGLCoordinateBounds bounds = MGLCoordinateBoundsFromLatLngBounds(_mbglMap->latLngBoundsForCamera(currentCameraOptions));
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsFromLatLngBounds(self.mbglMap.latLngBoundsForCamera(currentCameraOptions));
return [self cameraThatFitsCoordinateBounds:bounds];
}
@@ -1983,7 +2017,7 @@ public:
- (MGLMapCamera *)cameraByRotatingToDirection:(CLLocationDirection)degrees aroundAnchorPoint:(CGPoint)anchorPoint
{
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- mbgl::CameraOptions currentCameraOptions = _mbglMap->getCameraOptions(padding);
+ mbgl::CameraOptions currentCameraOptions = self.mbglMap.getCameraOptions(padding);
MGLMapCamera *camera;
@@ -1998,7 +2032,7 @@ public:
- (MGLMapCamera *)cameraByTiltingToPitch:(CGFloat)pitch
{
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- mbgl::CameraOptions currentCameraOptions = _mbglMap->getCameraOptions(padding);
+ mbgl::CameraOptions currentCameraOptions = self.mbglMap.getCameraOptions(padding);
MGLMapCamera *camera;
@@ -2292,7 +2326,7 @@ public:
NSString *symbolName = annotationImage.styleIconIdentifier;
// Update the annotation’s backing geometry to match the annotation model object. Any associated annotation view is also moved by side effect. However, -updateAnnotationViews disables the view’s animation actions, because it can’t distinguish between moves due to the viewport changing and moves due to the annotation’s coordinate changing.
- _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String });
+ self.mbglMap.updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String });
[self updateCalloutView];
}
}
@@ -2310,7 +2344,7 @@ public:
if (annotation == [self annotationWithTag:annotationTag])
{
// Update the annotation’s backing geometry to match the annotation model object.
- _mbglMap->updateAnnotation(annotationTag, [annotation annotationObjectWithDelegate:self]);
+ self.mbglMap.updateAnnotation(annotationTag, [annotation annotationObjectWithDelegate:self]);
[self updateCalloutView];
}
}
@@ -2338,7 +2372,13 @@ public:
- (MGLMapDebugMaskOptions)debugMask
{
- mbgl::MapDebugOptions options = _mbglMap->getDebug();
+ if (!_mbglMap)
+ {
+ NSAssert(self.terminated, @"_mbglMap should only be unavailable during app termination");
+ return self.residualDebugMask;
+ }
+
+ mbgl::MapDebugOptions options = self.mbglMap.getDebug();
MGLMapDebugMaskOptions mask = 0;
if (options & mbgl::MapDebugOptions::TileBorders)
{
@@ -2365,6 +2405,11 @@ public:
- (void)setDebugMask:(MGLMapDebugMaskOptions)debugMask
{
+ if (!_mbglMap)
+ {
+ return;
+ }
+
mbgl::MapDebugOptions options = mbgl::MapDebugOptions::NoDebug;
if (debugMask & MGLMapDebugTileBoundariesMask)
{
@@ -2386,7 +2431,7 @@ public:
{
options |= mbgl::MapDebugOptions::Overdraw;
}
- _mbglMap->setDebug(options);
+ self.mbglMap.setDebug(options);
}
- (void)resetNorth
@@ -2403,7 +2448,7 @@ public:
- (void)resetPosition
{
MGLLogInfo(@"Resetting the map to the current style’s default viewport.");
- auto camera = _mbglMap->getStyle().getDefaultCamera();
+ auto camera = self.mbglMap.getStyle().getDefaultCamera();
CGFloat pitch = *camera.pitch;
CLLocationDirection heading = mbgl::util::wrap(*camera.angle, 0., 360.);
CLLocationDistance altitude = MGLAltitudeForZoomLevel(*camera.zoom, pitch, 0, self.frame.size);
@@ -2977,7 +3022,7 @@ public:
centerPoint = self.userLocationAnnotationViewCenter;
}
double newZoom = round(self.zoomLevel) + log2(scaleFactor);
- _mbglMap->setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ self.mbglMap.setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
[self unrotateIfNeededForGesture];
_accessibilityValueAnnouncementIsPending = YES;
@@ -3005,7 +3050,7 @@ public:
- (CLLocationCoordinate2D)centerCoordinate
{
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- return MGLLocationCoordinate2DFromLatLng(_mbglMap->getLatLng(padding));
+ return MGLLocationCoordinate2DFromLatLng(self.mbglMap.getLatLng(padding));
}
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated
@@ -3048,6 +3093,15 @@ public:
- (void)_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate edgePadding:(UIEdgeInsets)insets zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
+ if (!_mbglMap)
+ {
+ if (completion)
+ {
+ completion();
+ }
+ return;
+ }
+
mbgl::CameraOptions cameraOptions;
cameraOptions.center = MGLLatLngFromLocationCoordinate2D(centerCoordinate);
cameraOptions.padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
@@ -3091,7 +3145,7 @@ public:
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
- _mbglMap->easeTo(cameraOptions, animationOptions);
+ self.mbglMap.easeTo(cameraOptions, animationOptions);
}
+ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomLevel
@@ -3101,7 +3155,7 @@ public:
- (double)zoomLevel
{
- return _mbglMap->getZoom();
+ return self.mbglMap.getZoom();
}
- (void)setZoomLevel:(double)zoomLevel
@@ -3120,31 +3174,31 @@ public:
CGFloat duration = animated ? MGLAnimationDuration : 0;
- _mbglMap->setZoom(zoomLevel,
- MGLEdgeInsetsFromNSEdgeInsets(self.contentInset),
- MGLDurationFromTimeInterval(duration));
+ self.mbglMap.setZoom(zoomLevel,
+ MGLEdgeInsetsFromNSEdgeInsets(self.contentInset),
+ MGLDurationFromTimeInterval(duration));
}
- (void)setMinimumZoomLevel:(double)minimumZoomLevel
{
MGLLogDebug(@"Setting minimumZoomLevel: %f", minimumZoomLevel);
- _mbglMap->setMinZoom(minimumZoomLevel);
+ self.mbglMap.setMinZoom(minimumZoomLevel);
}
- (double)minimumZoomLevel
{
- return _mbglMap->getMinZoom();
+ return self.mbglMap.getMinZoom();
}
- (void)setMaximumZoomLevel:(double)maximumZoomLevel
{
MGLLogDebug(@"Setting maximumZoomLevel: %f", maximumZoomLevel);
- _mbglMap->setMaxZoom(maximumZoomLevel);
+ self.mbglMap.setMaxZoom(maximumZoomLevel);
}
- (double)maximumZoomLevel
{
- return _mbglMap->getMaxZoom();
+ return self.mbglMap.getMaxZoom();
}
- (MGLCoordinateBounds)visibleCoordinateBounds
@@ -3243,6 +3297,15 @@ public:
- (void)_setVisibleCoordinates:(const CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
+ if (!_mbglMap)
+ {
+ if (completion)
+ {
+ completion();
+ }
+ return;
+ }
+
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
std::vector<mbgl::LatLng> latLngs;
@@ -3252,7 +3315,7 @@ public:
latLngs.push_back({coordinates[i].latitude, coordinates[i].longitude});
}
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngs(latLngs, padding);
+ mbgl::CameraOptions cameraOptions = self.mbglMap.cameraForLatLngs(latLngs, padding);
if (direction >= 0)
{
cameraOptions.angle = direction;
@@ -3290,7 +3353,7 @@ public:
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
- _mbglMap->easeTo(cameraOptions, animationOptions);
+ self.mbglMap.easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"visibleCoordinateBounds"];
}
@@ -3301,7 +3364,7 @@ public:
- (CLLocationDirection)direction
{
- return mbgl::util::wrap(_mbglMap->getBearing(), 0., 360.);
+ return mbgl::util::wrap(self.mbglMap.getBearing(), 0., 360.);
}
- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated
@@ -3319,6 +3382,11 @@ public:
- (void)_setDirection:(CLLocationDirection)direction animated:(BOOL)animated
{
+ if (!_mbglMap)
+ {
+ return;
+ }
+
if (direction == self.direction) return;
[self cancelTransitions];
@@ -3328,14 +3396,14 @@ public:
if (self.userTrackingMode == MGLUserTrackingModeNone)
{
- _mbglMap->setBearing(direction,
+ self.mbglMap.setBearing(direction,
MGLEdgeInsetsFromNSEdgeInsets(self.contentInset),
MGLDurationFromTimeInterval(duration));
}
else
{
CGPoint centerPoint = self.userLocationAnnotationViewCenter;
- _mbglMap->setBearing(direction, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y },
+ self.mbglMap.setBearing(direction, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y },
MGLDurationFromTimeInterval(duration));
}
}
@@ -3358,8 +3426,14 @@ public:
- (MGLMapCamera *)camera
{
+ if (!_mbglMap)
+ {
+ NSAssert(self.terminated, @"_mbglMap should only be unavailable during app termination");
+ return self.residualCamera;
+ }
+
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- return [self cameraForCameraOptions:_mbglMap->getCameraOptions(padding)];
+ return [self cameraForCameraOptions:self.mbglMap.getCameraOptions(padding)];
}
- (void)setCamera:(MGLMapCamera *)camera
@@ -3387,7 +3461,17 @@ public:
}
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function edgePadding:(UIEdgeInsets)edgePadding completionHandler:(nullable void (^)(void))completion {
+ if (!_mbglMap)
+ {
+ if (completion)
+ {
+ completion();
+ }
+ return;
+ }
+
MGLLogDebug(@"Setting camera: %@ duration: %f animationTimingFunction: %@ edgePadding: %@ completionHandler: %@", camera, duration, function, NSStringFromUIEdgeInsets(edgePadding), completion);
+
mbgl::AnimationOptions animationOptions;
if (duration > 0)
{
@@ -3420,7 +3504,7 @@ public:
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:edgePadding];
- _mbglMap->easeTo(cameraOptions, animationOptions);
+ self.mbglMap.easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
}
@@ -3444,6 +3528,15 @@ public:
- (void)_flyToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion
{
+ if (!_mbglMap)
+ {
+ if (completion)
+ {
+ completion();
+ }
+ return;
+ }
+
mbgl::AnimationOptions animationOptions;
if (duration >= 0)
{
@@ -3482,13 +3575,17 @@ public:
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:insets];
- _mbglMap->flyTo(cameraOptions, animationOptions);
+ self.mbglMap.flyTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
}
- (void)cancelTransitions {
+ if (!_mbglMap)
+ {
+ return;
+ }
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonTransitionCancelled;
- _mbglMap->cancelTransitions();
+ self.mbglMap.cancelTransitions();
self.cameraChangeReasonBitmask &= ~MGLCameraChangeReasonTransitionCancelled;
}
@@ -3499,14 +3596,24 @@ public:
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets
{
+ if (!_mbglMap)
+ {
+ return nil;
+ }
+
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding);
+ mbgl::CameraOptions cameraOptions = self.mbglMap.cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding);
return [self cameraForCameraOptions:cameraOptions];
}
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets
{
+ if (!_mbglMap)
+ {
+ return nil;
+ }
+
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
@@ -3514,11 +3621,16 @@ public:
CGFloat pitch = camera.pitch < 0 ? currentCamera.pitch : camera.pitch;
CLLocationDirection direction = camera.heading < 0 ? currentCamera.heading : camera.heading;
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding, direction, pitch);
+ mbgl::CameraOptions cameraOptions = self.mbglMap.cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding, direction, pitch);
return [self cameraForCameraOptions:cameraOptions];
}
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingShape:(MGLShape *)shape edgePadding:(UIEdgeInsets)insets {
+ if (!_mbglMap)
+ {
+ return nil;
+ }
+
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
@@ -3526,26 +3638,36 @@ public:
CGFloat pitch = camera.pitch < 0 ? currentCamera.pitch : camera.pitch;
CLLocationDirection direction = camera.heading < 0 ? currentCamera.heading : camera.heading;
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForGeometry([shape geometryObject], padding, direction, pitch);
+ mbgl::CameraOptions cameraOptions = self.mbglMap.cameraForGeometry([shape geometryObject], padding, direction, pitch);
return [self cameraForCameraOptions: cameraOptions];
}
- (MGLMapCamera *)cameraThatFitsShape:(MGLShape *)shape direction:(CLLocationDirection)direction edgePadding:(UIEdgeInsets)insets {
+ if (!_mbglMap)
+ {
+ return nil;
+ }
+
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForGeometry([shape geometryObject], padding, direction);
+ mbgl::CameraOptions cameraOptions = self.mbglMap.cameraForGeometry([shape geometryObject], padding, direction);
return [self cameraForCameraOptions:cameraOptions];
}
- (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions
{
- CLLocationCoordinate2D centerCoordinate = MGLLocationCoordinate2DFromLatLng(cameraOptions.center ? *cameraOptions.center : _mbglMap->getLatLng());
+ if (!_mbglMap)
+ {
+ return nil;
+ }
+
+ CLLocationCoordinate2D centerCoordinate = MGLLocationCoordinate2DFromLatLng(cameraOptions.center ? *cameraOptions.center : self.mbglMap.getLatLng());
double zoomLevel = cameraOptions.zoom ? *cameraOptions.zoom : self.zoomLevel;
CLLocationDirection direction = cameraOptions.angle ? mbgl::util::wrap(*cameraOptions.angle, 0., 360.) : self.direction;
- CGFloat pitch = cameraOptions.pitch ? *cameraOptions.pitch : _mbglMap->getPitch();
+ CGFloat pitch = cameraOptions.pitch ? *cameraOptions.pitch : self.mbglMap.getPitch();
CLLocationDistance altitude = MGLAltitudeForZoomLevel(zoomLevel, pitch, centerCoordinate.latitude, self.frame.size);
return [MGLMapCamera cameraLookingAtCenterCoordinate:centerCoordinate altitude:altitude pitch:pitch heading:direction];
}
@@ -3583,7 +3705,7 @@ public:
- (mbgl::LatLng)convertPoint:(CGPoint)point toLatLngFromView:(nullable UIView *)view
{
CGPoint convertedPoint = [self convertPoint:point fromView:view];
- return _mbglMap->latLngForPixel(mbgl::ScreenCoordinate(convertedPoint.x, convertedPoint.y)).wrapped();
+ return self.mbglMap.latLngForPixel(mbgl::ScreenCoordinate(convertedPoint.x, convertedPoint.y)).wrapped();
}
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable UIView *)view
@@ -3598,7 +3720,7 @@ public:
/// Converts a geographic coordinate to a point in the view’s coordinate system.
- (CGPoint)convertLatLng:(mbgl::LatLng)latLng toPointToView:(nullable UIView *)view
{
- mbgl::ScreenCoordinate pixel = _mbglMap->pixelForLatLng(latLng);
+ mbgl::ScreenCoordinate pixel = self.mbglMap.pixelForLatLng(latLng);
return [self convertPoint:CGPointMake(pixel.x, pixel.y) toView:view];
}
@@ -3816,7 +3938,7 @@ public:
}
_isChangingAnnotationLayers = YES;
- MGLAnnotationTag annotationTag = _mbglMap->addAnnotation([multiPoint annotationObjectWithDelegate:self]);
+ MGLAnnotationTag annotationTag = self.mbglMap.addAnnotation([multiPoint annotationObjectWithDelegate:self]);
MGLAnnotationContext context;
context.annotation = annotation;
_annotationContextsByAnnotationTag[annotationTag] = context;
@@ -3884,7 +4006,7 @@ public:
annotationImagesForAnnotation[annotationValue] = annotationImage;
}
- MGLAnnotationTag annotationTag = _mbglMap->addAnnotation(mbgl::SymbolAnnotation {
+ MGLAnnotationTag annotationTag = self.mbglMap.addAnnotation(mbgl::SymbolAnnotation {
MGLPointFromLocationCoordinate2D(annotation.coordinate),
symbolName.UTF8String
});
@@ -4063,7 +4185,7 @@ public:
annotationImage.delegate = self;
// add sprite
- _mbglMap->addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
+ self.mbglMap.addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
// Create a slop area with a “radius” equal in size to the annotation
// image’s alignment rect, allowing the eventual tap to be on any point
@@ -4137,7 +4259,7 @@ public:
}
_isChangingAnnotationLayers = YES;
- _mbglMap->removeAnnotation(annotationTag);
+ self.mbglMap.removeAnnotation(annotationTag);
}
[self didChangeValueForKey:@"annotations"];
@@ -4889,7 +5011,7 @@ public:
if ([pair.second.imageReuseIdentifier isEqualToString:reuseIdentifier])
{
const mbgl::Point<double> point = MGLPointFromLocationCoordinate2D(pair.second.annotation.coordinate);
- _mbglMap->updateAnnotation(pair.first, mbgl::SymbolAnnotation { point, iconIdentifier.UTF8String ?: "" });
+ self.mbglMap.updateAnnotation(pair.first, mbgl::SymbolAnnotation { point, iconIdentifier.UTF8String ?: "" });
}
}
}
@@ -5610,7 +5732,7 @@ public:
- (CGFloat)currentMinimumZoom
{
- return fmaxf(_mbglMap->getMinZoom(), MGLMinimumZoom);
+ return fmaxf(self.mbglMap.getMinZoom(), MGLMinimumZoom);
}
- (BOOL)isRotationAllowed
@@ -5670,7 +5792,8 @@ public:
}
- (void)cameraWillChangeAnimated:(BOOL)animated {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5704,7 +5827,8 @@ public:
}
- (void)cameraIsChanging {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5722,7 +5846,8 @@ public:
}
- (void)cameraDidChangeAnimated:(BOOL)animated {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5768,7 +5893,8 @@ public:
}
- (void)mapViewWillStartLoadingMap {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5779,7 +5905,8 @@ public:
}
- (void)mapViewDidFinishLoadingMap {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5794,7 +5921,8 @@ public:
}
- (void)mapViewDidFailLoadingMapWithError:(NSError *)error {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5805,7 +5933,8 @@ public:
}
- (void)mapViewWillStartRenderingFrame {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5816,7 +5945,8 @@ public:
}
- (void)mapViewDidFinishRenderingFrameFullyRendered:(BOOL)fullyRendered {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5833,7 +5963,8 @@ public:
}
- (void)mapViewWillStartRenderingMap {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5844,7 +5975,8 @@ public:
}
- (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
@@ -5857,11 +5989,12 @@ public:
}
- (void)didFinishLoadingStyle {
- if (!_mbglMap) {
+ if (!_mbglMap)
+ {
return;
}
- self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() mapView:self];
+ self.style = [[MGLStyle alloc] initWithRawStyle:&self.mbglMap.getStyle() mapView:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];
@@ -6200,7 +6333,7 @@ public:
- (BOOL)isFullyLoaded
{
- return _mbglMap->isFullyLoaded();
+ return self.mbglMap.isFullyLoaded();
}
- (void)prepareForInterfaceBuilder
diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h
index 133d17023e..bddb9b093e 100644
--- a/platform/ios/src/MGLMapView_Private.h
+++ b/platform/ios/src/MGLMapView_Private.h
@@ -8,6 +8,9 @@ namespace mbgl {
/// Minimum size of an annotation’s accessibility element.
FOUNDATION_EXTERN const CGSize MGLAnnotationAccessibilityElementMinimumSize;
+/// Indicates that a method (that uses `mbgl::Map`) was called after app termination.
+FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLUnderlyingMapUnavailableException;
+
@interface MGLMapView (Private)
/// Currently shown popover representing the selected annotation.
@@ -16,8 +19,6 @@ FOUNDATION_EXTERN const CGSize MGLAnnotationAccessibilityElementMinimumSize;
/** Triggers another render pass even when it is not necessary. */
- (void)setNeedsGLDisplay;
-- (mbgl::Map *)mbglMap;
-
- (mbgl::Renderer *)renderer;
/** Returns whether the map view is currently loading or processing any assets required to render the map */