Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios, macos] Make MGLMapView.style property nullable (#7664)
Browse files Browse the repository at this point in the history
* [ios, macos] Made MGLMapView.style property nullable

MGLMapView’s style property is now nullable (optional in Swift). The property is set to nil while the style loads and in the event that the style has failed to load.

* [ios, macos] Switch to delegate method

* [macos] Create MGLMapView programmatically for layer tests

When MGLMapView is created via a nib, -initWithCoder: is called, causing styleURL to be set to nil, in turn causing the default Streets style to be loaded, fooling MGLStyleLayerTests into thinking one-line has been loaded. Instead, create MGLMapView programmatically, passing the intended style URL into the initializer, preventing Streets from being loaded.
  • Loading branch information
1ec5 authored Jan 11, 2017
1 parent 581fb38 commit 424c124
Show file tree
Hide file tree
Showing 18 changed files with 99 additions and 90 deletions.
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLCircleStyleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
])
layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
```
*/
@interface MGLCircleStyleLayer : MGLVectorStyleLayer
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLFillStyleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
layer.sourceLayerIdentifier = "parks"
layer.fillColor = MGLStyleValue(rawValue: .green)
layer.predicate = NSPredicate(format: "type == %@", "national-park")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
```
*/
@interface MGLFillStyleLayer : MGLVectorStyleLayer
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLLineStyleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
layer.lineColor = MGLStyleValue(rawValue: .brown)
layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
```
*/
@interface MGLLineStyleLayer : MGLVectorStyleLayer
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLRasterSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ extern const MGLTileSourceOption MGLTileSourceOptionTileSize;
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style.addSource(source)
mapView.style?.addSource(source)
```
*/
@interface MGLRasterSource : MGLTileSource
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLRasterStyleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
```swift
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
```
*/
@interface MGLRasterStyleLayer : MGLForegroundStyleLayer
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLShapeSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
let shape = MGLShapeCollectionFeature(shapes: [polyline])
let source = MGLShapeSource(identifier: "lines", shape: shape, options: nil)
mapView.style.addSource(source)
mapView.style?.addSource(source)
```
*/
@interface MGLShapeSource : MGLSource
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLSymbolStyleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
```
*/
@interface MGLSymbolStyleLayer : MGLVectorStyleLayer
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLVectorSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style.addSource(source)
mapView.style?.addSource(source)
```
*/
@interface MGLVectorSource : MGLTileSource
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLVectorStyleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ NS_ASSUME_NONNULL_BEGIN
let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
layer.sourceLayerIdentifier = "contours"
layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
```
*/
@property (nonatomic, nullable) NSPredicate *predicate;
Expand Down
48 changes: 24 additions & 24 deletions platform/darwin/test/MGLDocumentationExampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
let shape = MGLShapeCollectionFeature(shapes: [polyline])
let source = MGLShapeSource(identifier: "lines", shape: shape, options: nil)
mapView.style.addSource(source)
mapView.style?.addSource(source)
//#-end-example-code

XCTAssertNotNil(mapView.style.source(withIdentifier: "lines"))
XCTAssertNotNil(mapView.style?.source(withIdentifier: "lines"))
}

func testMGLRasterSource() {
Expand All @@ -84,10 +84,10 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style.addSource(source)
mapView.style?.addSource(source)
//#-end-example-code

XCTAssertNotNil(mapView.style.source(withIdentifier: "clouds"))
XCTAssertNotNil(mapView.style?.source(withIdentifier: "clouds"))
}

func testMGLVectorSource() {
Expand All @@ -99,15 +99,15 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style.addSource(source)
mapView.style?.addSource(source)
//#-end-example-code

XCTAssertNotNil(mapView.style.source(withIdentifier: "pois"))
XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois"))
}

func testMGLCircleStyleLayer() {
let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style.addSource(population)
mapView.style?.addSource(population)

//#-example-code
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
Expand All @@ -119,15 +119,15 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
])
layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
//#-end-example-code

XCTAssertNotNil(mapView.style.layer(withIdentifier: "circles"))
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "circles"))
}

func testMGLLineStyleLayer() {
let trails = MGLVectorSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style.addSource(trails)
mapView.style?.addSource(trails)

//#-example-code
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
Expand All @@ -139,30 +139,30 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
layer.lineColor = MGLStyleValue(rawValue: .brown)
layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
//#-end-example-code

XCTAssertNotNil(mapView.style.layer(withIdentifier: "trails-path"))
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "trails-path"))
}

func testMGLFillStyleLayer() {
let parks = MGLVectorSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style.addSource(parks)
mapView.style?.addSource(parks)

//#-example-code
let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
layer.sourceLayerIdentifier = "parks"
layer.fillColor = MGLStyleValue(rawValue: .green)
layer.predicate = NSPredicate(format: "type == %@", "national-park")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
//#-end-example-code

XCTAssertNotNil(mapView.style.layer(withIdentifier: "parks"))
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "parks"))
}

func testMGLSymbolStyleLayer() {
let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style.addSource(pois)
mapView.style?.addSource(pois)

//#-example-code
let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
Expand All @@ -179,10 +179,10 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
//#-end-example-code

XCTAssertNotNil(mapView.style.layer(withIdentifier: "coffeeshops"))
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "coffeeshops"))
}

func testMGLRasterStyleLayer() {
Expand All @@ -194,28 +194,28 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style.addSource(source)
mapView.style?.addSource(source)

//#-example-code
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
//#-end-example-code

XCTAssertNotNil(mapView.style.layer(withIdentifier: "clouds"))
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "clouds"))
}

func testMGLVectorStyleLayer$predicate() {
let terrain = MGLVectorSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style.addSource(terrain)
mapView.style?.addSource(terrain)

//#-example-code
let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
layer.sourceLayerIdentifier = "contours"
layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
mapView.style.addLayer(layer)
mapView.style?.addLayer(layer)
//#-end-example-code

XCTAssertNotNil(mapView.style.layer(withIdentifier: "contour"))
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "contour"))
}
}
1 change: 0 additions & 1 deletion platform/darwin/test/MGLStyleLayerTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
@interface MGLStyleLayerTests : XCTestCase <MGLMapViewDelegate>

@property (nonatomic) IBOutlet MGLMapView *mapView;
@property (nonatomic) XCTestExpectation *expectation;
@property (nonatomic, copy, readonly, class) NSString *layerType;

- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean;
Expand Down
13 changes: 11 additions & 2 deletions platform/darwin/test/MGLStyleLayerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,27 @@ @implementation MGLStyleLayerTests
- (void)setUp {
[super setUp];
[MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
#if TARGET_OS_IPHONE
UIApplication *app = [UIApplication sharedApplication];
UIViewController *vc = [[UIViewController alloc] init];
app.keyWindow.rootViewController = vc;
[vc view]; // Force load xib
_mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 256, 256)];
_mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 256, 256) styleURL:styleURL];
[vc.view addSubview:_mapView];
_mapView.delegate = self;
#else
NSWindowController *windowController = [[NSWindowController alloc] initWithWindowNibName:@"MGLStyleLayerTests" owner:self];
NSView *contentView = windowController.window.contentView;
_mapView = [[MGLMapView alloc] initWithFrame:contentView.bounds styleURL:styleURL];
[contentView addSubview:_mapView];
[windowController showWindow:nil];
#endif
_mapView.delegate = self;
XCTAssertNil(_mapView.style);
[self keyValueObservingExpectationForObject:self.mapView keyPath:@"style" handler:^BOOL(MGLMapView * _Nonnull observedMapView, NSDictionary * _Nonnull change) {
return observedMapView.style != nil;
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
}

- (void)tearDown {
Expand Down
29 changes: 6 additions & 23 deletions platform/darwin/test/MGLStyleLayerTests.xib
Original file line number Diff line number Diff line change
@@ -1,38 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16A304a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1212" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MGLMapViewTests">
<connections>
<outlet property="mapView" destination="6RL-d9-juy" id="0ch-aR-Um6"/>
</connections>
</customObject>
<customObject id="-2" userLabel="File's Owner" customClass="MGLMapViewTests"/>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="MGLMapViewTests" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="256" height="256"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1058"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="256" height="256"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="6RL-d9-juy" customClass="MGLMapView">
<rect key="frame" x="0.0" y="0.0" width="256" height="256"/>
<connections>
<outlet property="delegate" destination="-2" id="6kS-ct-JEg"/>
</connections>
</customView>
</subviews>
<constraints>
<constraint firstItem="6RL-d9-juy" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="KEN-aL-UF0"/>
<constraint firstAttribute="bottom" secondItem="6RL-d9-juy" secondAttribute="bottom" id="V27-f3-xHZ"/>
<constraint firstAttribute="trailing" secondItem="6RL-d9-juy" secondAttribute="trailing" id="vjq-iM-OyA"/>
<constraint firstItem="6RL-d9-juy" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="yWg-v4-wJB"/>
</constraints>
</view>
</window>
</objects>
Expand Down
22 changes: 16 additions & 6 deletions platform/darwin/test/MGLStyleTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ - (void)setUp {
[super setUp];

[MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) styleURL:styleURL];
XCTAssertNil(self.mapView.style);
[self keyValueObservingExpectationForObject:self.mapView keyPath:@"style" handler:^BOOL(MGLMapView * _Nonnull observedMapView, NSDictionary * _Nonnull change) {
return observedMapView.style != nil;
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
}

- (void)tearDown {
Expand Down Expand Up @@ -250,12 +256,16 @@ - (void)testLayersOrder {
[self.style insertLayer:layer0 belowLayer:layer1];

NSArray<MGLStyleLayer *> *layers = [self.style layers];
NSUInteger startIndex = 0;
if ([layers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) {
startIndex++;
}

XCTAssert([[layers[0] identifier] isEqualToString:layer0.identifier]);
XCTAssert([[layers[1] identifier] isEqualToString:layer1.identifier]);
XCTAssert([[layers[2] identifier] isEqualToString:layer2.identifier]);
XCTAssert([[layers[3] identifier] isEqualToString:layer3.identifier]);
XCTAssert([[layers[4] identifier] isEqualToString:layer4.identifier]);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer0.identifier);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer1.identifier);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer2.identifier);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer3.identifier);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer4.identifier);
}

@end
9 changes: 8 additions & 1 deletion platform/ios/src/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,21 @@ IB_DESIGNABLE
Unlike the `styleURL` property, this property is set to an object that allows
you to manipulate every aspect of the style locally.
If the style is loading, this property is set to `nil` until the style finishes
loading. If the style has failed to load, this property is set to `nil`.
Because the style loads asynchronously, you should manipulate it in the
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible
to manipulate the style before it has finished loading.
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
manipulate a style's sources and layers must first set the style URL to an
explicitly versioned style using a convenience method like
`+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`.
*/
@property (nonatomic, readonly) MGLStyle *style;
@property (nonatomic, readonly, nullable) MGLStyle *style;

/**
URLs of the styles bundled with the library.
Expand Down
Loading

0 comments on commit 424c124

Please sign in to comment.