[ios, macos] Raise NSException if layer or source added more than once

When MGLSource and MGLLayer instances are added to the style, they lose
ownership of their std::unique_ptr<T> after it is moved to the mbgl
level. Subsequent attempts to add such instances result in a C++
exception.

This adds logic in the Darwin platform to raise a NSException if the
source and layer addToMapView methods are called more than once and the
pointer is invalid. In addition, the documentation in MGLStyle for
addSource: and addLayer: has been update to warn developers to avoid
adding the same instance twice and, for that matter, instances with the
same identifier.
This commit is contained in:
Jesse Bounds
2016-12-01 21:20:53 -08:00
parent 2db31be8bc
commit 1db0a96927
12 changed files with 135 additions and 1 deletions

View File

@@ -35,6 +35,12 @@
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -75,6 +75,12 @@ namespace mbgl {
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -70,6 +70,12 @@ namespace mbgl {
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -61,6 +61,12 @@ const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance = @"M
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
}
mapView.mbglMap->addSource(std::move(_pendingSource));
}

View File

@@ -82,6 +82,12 @@ namespace mbgl {
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -62,6 +62,12 @@
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
}
mapView.mbglMap->addSource(std::move(_pendingSource));
}

View File

@@ -34,6 +34,12 @@
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -200,6 +200,9 @@ static const NSInteger MGLStyleDefaultVersion = 9;
/**
Adds a new source to the current style.
@note Adding the same source instance more than once or reusing source
identifers in the sources you add will trigger exceptions.
@param source The source to add to the current style.
*/
- (void)addSource:(MGLSource *)source;
@@ -247,6 +250,9 @@ static const NSInteger MGLStyleDefaultVersion = 9;
/**
Adds a new layer on top of existing layers.
@note Adding the same layer instance more than once or reusing layer
identifers in the layers you add will trigger exceptions.
@param layer The layer object to add to the map view. This object must be an
instance of a concrete subclass of `MGLStyleLayer`.
*/
@@ -255,6 +261,9 @@ static const NSInteger MGLStyleDefaultVersion = 9;
/**
Inserts a new layer into the style at the given index.
@note Adding the same layer instance more than once or reusing layer
identifers in the layers you add will trigger exceptions.
@param layer The layer to insert.
@param index The index at which to insert the layer. An index of 0 would send
the layer to the back; an index equal to the number of objects in the
@@ -272,6 +281,9 @@ static const NSInteger MGLStyleDefaultVersion = 9;
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
Adding the same layer instance more than once or reusing layer identifers in
the layers you add will trigger exceptions.
@param layer The layer to insert.
@param sibling An existing layer in the style.
@@ -288,6 +300,9 @@ static const NSInteger MGLStyleDefaultVersion = 9;
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
Adding the same layer instance more than once or reusing layer identifers in
the layers you add will trigger exceptions.
@param layer The layer to insert.
@param sibling An existing layer in the style.

View File

@@ -112,6 +112,12 @@ namespace mbgl {
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -129,6 +129,12 @@ namespace mbgl {
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}

View File

@@ -59,6 +59,12 @@
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
}
mapView.mbglMap->addSource(std::move(_pendingSource));
}

View File

@@ -1,4 +1,16 @@
#import "MGLStyle.h"
#import "MGLMapView.h"
#import "MGLStyle_Private.h"
#import "MGLGeoJSONSource.h"
#import "MGLRasterSource.h"
#import "MGLVectorSource.h"
#import "MGLBackgroundStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLFillStyleLayer.h"
#import "MGLLineStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
#import "NSBundle+MGLAdditions.h"
@@ -92,6 +104,53 @@
}];
}
- (void)testAddingSourcesTwice {
MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
MGLStyle *style = [[MGLStyle alloc] initWithMapView:mapView];
MGLGeoJSONSource *geoJSONSource = [[MGLGeoJSONSource alloc] initWithIdentifier:@"geoJSONSource" features:@[] options:nil];
[style addSource:geoJSONSource];
XCTAssertThrowsSpecificNamed([style addSource:geoJSONSource], NSException, @"MGLRedundantSourceException");
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"rasterSource" URL:[NSURL new] tileSize:42];
[style addSource:rasterSource];
XCTAssertThrowsSpecificNamed([style addSource:rasterSource], NSException, @"MGLRedundantSourceException");
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"vectorSource" URL:[NSURL new]];
[style addSource:vectorSource];
XCTAssertThrowsSpecificNamed([style addSource:vectorSource], NSException, @"MGLRedundantSourceException");
}
- (void)testAddingLayersTwice {
MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
MGLStyle *style = [[MGLStyle alloc] initWithMapView:mapView];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"geoJSONSource" features:@[] options:nil];
MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"backgroundLayer"];
[style addLayer:backgroundLayer];
XCTAssertThrowsSpecificNamed([style addLayer:backgroundLayer], NSException, @"MGLRedundantLayerException");
MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayer" source:source];
[style addLayer:circleLayer];
XCTAssertThrowsSpecificNamed([style addLayer:circleLayer], NSException, @"MGLRedundantLayerException");
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:source];
[style addLayer:fillLayer];
XCTAssertThrowsSpecificNamed([style addLayer:fillLayer], NSException, @"MGLRedundantLayerException");
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayer" source:source];
[style addLayer:lineLayer];
XCTAssertThrowsSpecificNamed([style addLayer:lineLayer], NSException, @"MGLRedundantLayerException");
MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"rasterLayer" source:source];
[style addLayer:rasterLayer];
XCTAssertThrowsSpecificNamed([style addLayer:rasterLayer], NSException, @"MGLRedundantLayerException");
MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbolLayer" source:source];
[style addLayer:symbolLayer];
XCTAssertThrowsSpecificNamed([style addLayer:symbolLayer], NSException, @"MGLRedundantLayerException");
}
- (NSString *)stringWithContentsOfStyleHeader {
NSURL *styleHeaderURL = [[[NSBundle mgl_frameworkBundle].bundleURL
URLByAppendingPathComponent:@"Headers" isDirectory:YES]