summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorJesse Bounds <jesse@rebounds.net>2016-09-22 17:30:47 -0700
committerGitHub <noreply@github.com>2016-09-22 17:30:47 -0700
commit3ddb8dfc86753120d2ea2c3befdf2430c1c56562 (patch)
treebc241d8c66ea7f78ae4728f9644673e8994e1295 /platform
parent08c08f6705d168f0bc7cde251cdacb2c4a53bb7a (diff)
downloadqtlocation-mapboxgl-3ddb8dfc86753120d2ea2c3befdf2430c1c56562.tar.gz
[ios, macos] Add tile template option to raster and vector sources
A new MGLTileSet class that wraps all available core Tileset options can be created and passed into the sources. The sources pass that tileset object along to core.
Diffstat (limited to 'platform')
-rw-r--r--platform/darwin/src/MGLRasterSource.h12
-rw-r--r--platform/darwin/src/MGLRasterSource.mm37
-rw-r--r--platform/darwin/src/MGLTileSet.h78
-rw-r--r--platform/darwin/src/MGLTileSet.mm87
-rw-r--r--platform/darwin/src/MGLTileSet_Private.h9
-rw-r--r--platform/darwin/src/MGLVectorSource.h10
-rw-r--r--platform/darwin/src/MGLVectorSource.mm31
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj22
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/ios/test/MGLTileSetTests.mm82
10 files changed, 360 insertions, 9 deletions
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h
index e563244bce..3b22257cb6 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterSource.h
@@ -1,10 +1,20 @@
#import "MGLSource.h"
+#import "MGLTypes.h"
+
+@class MGLTileSet;
+
+NS_ASSUME_NONNULL_BEGIN
@interface MGLRasterSource : MGLSource
@property (nonatomic, readonly, copy) NSURL *URL;
-@property (nonatomic, readonly, assign) CGFloat tileSize;
+@property (nonatomic, readonly, assign) NSUInteger tileSize;
+@property (nonatomic, readonly, nullable) MGLTileSet *tileSet;
- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier URL:(NSURL *)url tileSize:(CGFloat)tileSize;
+- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier tileSize:(CGFloat)tileSize tileSet:(MGLTileSet *)tileSet;
+
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm
index 15ca2fc558..06d5a9689c 100644
--- a/platform/darwin/src/MGLRasterSource.mm
+++ b/platform/darwin/src/MGLRasterSource.mm
@@ -1,12 +1,15 @@
#import "MGLRasterSource.h"
#import "MGLSource_Private.h"
+#import "MGLTileSet_Private.h"
+#import "NSURL+MGLAdditions.h"
#include <mbgl/style/sources/raster_source.hpp>
@implementation MGLRasterSource
-- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier URL:(NSURL *)url tileSize:(CGFloat)tileSize {
+- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier URL:(NSURL *)url tileSize:(CGFloat)tileSize
+{
if (self = [super initWithSourceIdentifier:sourceIdentifier]) {
_URL = url;
_tileSize = tileSize;
@@ -14,10 +17,34 @@
return self;
}
-- (std::unique_ptr<mbgl::style::Source>)mbglSource {
- auto source = std::make_unique<mbgl::style::RasterSource>(self.sourceIdentifier.UTF8String,
- self.URL.absoluteString.UTF8String,
- uint16_t(self.tileSize));
+- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier tileSize:(CGFloat)tileSize tileSet:(MGLTileSet *)tileSet;
+{
+ if (self = [super initWithSourceIdentifier:sourceIdentifier])
+ {
+ _tileSize = tileSize;
+ _tileSet = tileSet;
+ }
+ return self;
+}
+
+- (std::unique_ptr<mbgl::style::Source>)mbglSource
+{
+ std::unique_ptr<mbgl::style::RasterSource> source;
+
+ if (self.URL)
+ {
+ source = std::make_unique<mbgl::style::RasterSource>(self.sourceIdentifier.UTF8String,
+ self.URL.mgl_URLByStandardizingScheme.absoluteString.UTF8String,
+ uint16_t(self.tileSize));
+ }
+ else
+ {
+ source = std::make_unique<mbgl::style::RasterSource>(self.sourceIdentifier.UTF8String,
+ self.tileSet.mbglTileset,
+ uint16_t(self.tileSize));
+
+ }
+
return std::move(source);
}
diff --git a/platform/darwin/src/MGLTileSet.h b/platform/darwin/src/MGLTileSet.h
new file mode 100644
index 0000000000..5ae899d833
--- /dev/null
+++ b/platform/darwin/src/MGLTileSet.h
@@ -0,0 +1,78 @@
+#import <Foundation/Foundation.h>
+#import "MGLTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** These constants represent the scheme that the tile URL templates will use. */
+typedef NS_ENUM(NSUInteger, MGLTileSetScheme) {
+ MGLTileSetSchemeXYZ = 0,
+ MGLTileSetSchemeTMS
+};
+
+/**
+ The `MGLTileSet` class holds the tile URL template strings and associated
+ configuration for those strings. It can be passed to an `MGLVectorSource` or
+ `MGLRasterSource` instead of an `NSURL` representing a TileJSON URL to create a
+ source.
+ */
+@interface MGLTileSet : NSObject
+
+/**
+ An `NSArray` of `NSString` objects that represent the tile templates.
+ */
+@property (nonatomic, copy) NS_ARRAY_OF(NSString *) *tileURLTemplates;
+
+/**
+ An `NSNumber` object containing an integer; specifies the minimum zoom level at
+ which the source will display tiles. The value should be in the range of 0 to
+ 22. The default value is 0 and the source will use the default value
+ if `minimumZoomLevel` is nil.
+ */
+@property (nonatomic, nullable) NSNumber *minimumZoomLevel;
+
+/**
+ An `NSNumber` object containing an integer; specifies the maximum zoom level at
+ which to display tiles. The value should be in the range of 0 to 22 and greater
+ than `minimumZoomLevel`. The default value is 22 and the source will use the
+ default value if `maximumZoomLevel` is nil.
+ */
+@property (nonatomic, nullable) NSNumber *maximumZoomLevel;
+
+/**
+ An `NSString` object that contains an attribution to be displayed when the map is
+ shown to a user. The default value is nil.
+ */
+@property (nonatomic, copy, nullable) NSString *attribution;
+
+/**
+ An `MGLTileSetScheme` value that contains an enumeration (either
+ `MGLTileSetSchemeXYZ` or `MGLTileSetSchemeTMS`) that influences the y direction
+ of the tile coordinates. The default is `MGLTileSetSchemeXYZ`.
+ */
+@property (nonatomic) MGLTileSetScheme scheme;
+
+/**
+ Initializes and returns a new tile set object.
+
+ @param tileURLTemplates An `NSArray` of `NSString` objects that represent the
+ tile templates.
+ @return The initialized tile set object.
+ */
+- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates;
+
+/**
+ Initializes and returns a new tile set object.
+
+ @param tileURLTemplates An `NSArray` of `NSString` objects that represent the
+ tile templates.
+ @param minimumZoomLevel An `NSUInteger`; specifies the minimum zoom level at
+ which to display tiles.
+ @param maximumZoomLevel An `NSUInteger`; specifies the maximum zoom level at
+ which to display tiles.
+ @return The initialized tile set object.
+ */
+- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLTileSet.mm b/platform/darwin/src/MGLTileSet.mm
new file mode 100644
index 0000000000..b2359bb92d
--- /dev/null
+++ b/platform/darwin/src/MGLTileSet.mm
@@ -0,0 +1,87 @@
+#import "MGLTileSet.h"
+
+#include <mbgl/util/tileset.hpp>
+
+@implementation MGLTileSet
+
+- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates
+{
+ if (self = [super init])
+ {
+ _tileURLTemplates = tileURLTemplates;
+ }
+ return self;
+}
+
+- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel
+{
+ if (minimumZoomLevel > maximumZoomLevel)
+ {
+ [[NSException exceptionWithName:@"Invalid minimumZoomLevel"
+ reason:@"minimumZoomLevel must be less than maximumZoomLevel"
+ userInfo:nil] raise];
+ return nil;
+ }
+
+ if (self = [super init])
+ {
+ _tileURLTemplates = tileURLTemplates;
+ _minimumZoomLevel = @(minimumZoomLevel);
+ _maximumZoomLevel = @(maximumZoomLevel);
+ }
+ return self;
+}
+
+- (void)setMinimumZoomLevel:(NSNumber *)minimumZoomLevel
+{
+ if (self.maximumZoomLevel && [minimumZoomLevel integerValue] > [self.maximumZoomLevel integerValue])
+ {
+ [[NSException exceptionWithName:@"Invalid minimumZoomLevel"
+ reason:@"minimumZoomLevel must be less than maximumZoomLevel"
+ userInfo:nil] raise];
+ return;
+ }
+
+ _minimumZoomLevel = minimumZoomLevel;
+}
+
+- (void)setMaximumZoomLevel:(NSNumber *)maximumZoomLevel
+{
+ if (self.maximumZoomLevel && [maximumZoomLevel integerValue] < [self.maximumZoomLevel integerValue])
+ {
+ [[NSException exceptionWithName:@"Invalid minimumZoomLevel"
+ reason:@"minimumZoomLevel must be less than maximumZoomLevel"
+ userInfo:nil] raise];
+ }
+
+ _maximumZoomLevel = maximumZoomLevel;
+}
+
+- (mbgl::Tileset)mbglTileset
+{
+ mbgl::Tileset tileset;
+
+ for (NSString *tileURLTemplate in self.tileURLTemplates)
+ {
+ tileset.tiles.push_back(tileURLTemplate.UTF8String);
+ }
+
+ // set the minimum / maximum zoom range to the values specified by this class if they
+ // were set. otherwise, use the core objects default values
+ uint8_t minimumZoomLevel = self.minimumZoomLevel ? [self.minimumZoomLevel unsignedIntegerValue] : tileset.zoomRange.min;
+ uint8_t maximumZoomLevel = self.minimumZoomLevel ? [self.maximumZoomLevel unsignedIntegerValue] : tileset.zoomRange.max;
+ tileset.zoomRange = mbgl::Range<uint8_t>(minimumZoomLevel, maximumZoomLevel);
+
+ if (self.attribution)
+ {
+ tileset.attribution = self.attribution.UTF8String;
+ }
+
+ if (self.scheme == MGLTileSetSchemeTMS) {
+ tileset.scheme = mbgl::Tileset::Scheme::TMS;
+ }
+
+ return tileset;
+}
+
+@end
diff --git a/platform/darwin/src/MGLTileSet_Private.h b/platform/darwin/src/MGLTileSet_Private.h
new file mode 100644
index 0000000000..6a14d428db
--- /dev/null
+++ b/platform/darwin/src/MGLTileSet_Private.h
@@ -0,0 +1,9 @@
+#import "MGLTileSet.h"
+
+#include <mbgl/util/tileset.hpp>
+
+@interface MGLTileSet (Private)
+
+- (mbgl::Tileset)mbglTileset;
+
+@end \ No newline at end of file
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h
index 05e041511e..2402208499 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorSource.h
@@ -1,4 +1,9 @@
#import "MGLSource.h"
+#import "MGLTypes.h"
+
+@class MGLTileSet;
+
+NS_ASSUME_NONNULL_BEGIN
/**
A vector tile source. Tiles must be in Mapbox Vector Tile format.
@@ -9,6 +14,7 @@
@interface MGLVectorSource : MGLSource
@property (nonatomic, readonly, copy) NSURL *URL;
+@property (nonatomic, readonly, nullable) MGLTileSet *tileSet;
/**
Initializes and returns a vector source from a remote url.
@@ -20,4 +26,8 @@
*/
- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier URL:(NSURL *)url;
+- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier tileSet:(MGLTileSet *)tileSet;
+
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index d0c9b0126a..2ab9627ef5 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -1,6 +1,8 @@
#import "MGLVectorSource.h"
#import "MGLSource_Private.h"
+#import "MGLTileSet_Private.h"
+#import "NSURL+MGLAdditions.h"
#include <mbgl/style/sources/vector_source.hpp>
@@ -8,16 +10,39 @@
static NSString *MGLVectorSourceType = @"vector";
-- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier URL:(NSURL *)url {
- if (self = [super initWithSourceIdentifier:sourceIdentifier]) {
+- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier URL:(NSURL *)url
+{
+ if (self = [super initWithSourceIdentifier:sourceIdentifier])
+ {
_URL = url;
}
return self;
}
+- (instancetype)initWithSourceIdentifier:(NSString *)sourceIdentifier tileSet:(MGLTileSet *)tileSet
+{
+ if (self = [super initWithSourceIdentifier:sourceIdentifier])
+ {
+ _tileSet = tileSet;
+ }
+ return self;
+}
+
- (std::unique_ptr<mbgl::style::Source>)mbglSource
{
- auto source = std::make_unique<mbgl::style::VectorSource>(self.sourceIdentifier.UTF8String, self.URL.absoluteString.UTF8String);
+ std::unique_ptr<mbgl::style::VectorSource> source;
+
+ if (self.URL)
+ {
+ source = std::make_unique<mbgl::style::VectorSource>(self.sourceIdentifier.UTF8String,
+ self.URL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
+ }
+ else
+ {
+ source = std::make_unique<mbgl::style::VectorSource>(self.sourceIdentifier.UTF8String,
+ self.tileSet.mbglTileset);
+ }
+
return std::move(source);
}
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 35a1075301..de77398582 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -159,6 +159,13 @@
4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */; };
+ 404C26E21D89B877000AA13D /* MGLTileSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E01D89B877000AA13D /* MGLTileSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404C26E31D89B877000AA13D /* MGLTileSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E01D89B877000AA13D /* MGLTileSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404C26E41D89B877000AA13D /* MGLTileSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = 404C26E11D89B877000AA13D /* MGLTileSet.mm */; };
+ 404C26E51D89B877000AA13D /* MGLTileSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = 404C26E11D89B877000AA13D /* MGLTileSet.mm */; };
+ 404C26E71D89C55D000AA13D /* MGLTileSet_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E61D89C515000AA13D /* MGLTileSet_Private.h */; };
+ 404C26E81D89C55D000AA13D /* MGLTileSet_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E61D89C515000AA13D /* MGLTileSet_Private.h */; };
+ 4085AF091D933DEA00F11B22 /* MGLTileSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */; };
40CFA6511D7875BB008103BD /* MGLGeoJSONSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40CFA6501D787579008103BD /* MGLGeoJSONSourceTests.mm */; };
40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */; };
40EDA1C11CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; };
@@ -568,6 +575,10 @@
4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView.h; sourceTree = "<group>"; };
402E9DE01CD2C76200FD4519 /* Mapbox.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Mapbox.playground; sourceTree = "<group>"; };
404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView_Private.h; sourceTree = "<group>"; };
+ 404C26E01D89B877000AA13D /* MGLTileSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSet.h; sourceTree = "<group>"; };
+ 404C26E11D89B877000AA13D /* MGLTileSet.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSet.mm; sourceTree = "<group>"; };
+ 404C26E61D89C515000AA13D /* MGLTileSet_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTileSet_Private.h; sourceTree = "<group>"; };
+ 4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSetTests.mm; sourceTree = "<group>"; };
40CFA6501D787579008103BD /* MGLGeoJSONSourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLGeoJSONSourceTests.mm; sourceTree = "<group>"; };
40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView.h; sourceTree = "<group>"; };
40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationContainerView.m; sourceTree = "<group>"; };
@@ -812,6 +823,9 @@
3566C7651D4A77BA008152BC /* MGLGeoJSONSource.mm */,
3566C76A1D4A8DFA008152BC /* MGLRasterSource.h */,
3566C76B1D4A8DFA008152BC /* MGLRasterSource.mm */,
+ 404C26E01D89B877000AA13D /* MGLTileSet.h */,
+ 404C26E61D89C515000AA13D /* MGLTileSet_Private.h */,
+ 404C26E11D89B877000AA13D /* MGLTileSet.mm */,
);
name = Sources;
sourceTree = "<group>";
@@ -927,6 +941,7 @@
isa = PBXGroup;
children = (
40CFA6501D787579008103BD /* MGLGeoJSONSourceTests.mm */,
+ 4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */,
);
name = Sources;
sourceTree = "<group>";
@@ -1453,11 +1468,13 @@
350098CA1D482D9C004B2AF0 /* NSArray+MGLStyleAttributeAdditions.h in Headers */,
350098AF1D47E6F4004B2AF0 /* UIColor+MGLStyleAttributeAdditions.h in Headers */,
3510FFF91D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
+ 404C26E71D89C55D000AA13D /* MGLTileSet_Private.h in Headers */,
DA88485C1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h in Headers */,
DA8848871CBB033F00AB86E3 /* Fabric.h in Headers */,
350098D81D4830D5004B2AF0 /* NSString+MGLStyleAttributeAdditions_Private.h in Headers */,
35305D4A1D22AA6A0007D005 /* NSData+MGLAdditions.h in Headers */,
359F57461D2FDDA6005217F1 /* MGLUserLocationAnnotationView_Private.h in Headers */,
+ 404C26E21D89B877000AA13D /* MGLTileSet.h in Headers */,
DA8848841CBB033F00AB86E3 /* FABAttributes.h in Headers */,
DA8847FD1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h in Headers */,
DA88482F1CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h in Headers */,
@@ -1489,6 +1506,7 @@
3566C7671D4A77BA008152BC /* MGLGeoJSONSource.h in Headers */,
DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */,
DABFB8711CBE9A0F00D62B32 /* MGLMapView+MGLCustomStyleLayerAdditions.h in Headers */,
+ 404C26E31D89B877000AA13D /* MGLTileSet.h in Headers */,
DABFB8611CBE99E500D62B32 /* MGLMultiPoint.h in Headers */,
3510FFF11D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */,
35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */,
@@ -1515,6 +1533,7 @@
350098B01D47E6F4004B2AF0 /* UIColor+MGLStyleAttributeAdditions.h in Headers */,
DABFB8671CBE99E500D62B32 /* MGLPolygon.h in Headers */,
350098C71D48288B004B2AF0 /* NSNumber+MGLStyleAttributeAdditions_Private.h in Headers */,
+ 404C26E81D89C55D000AA13D /* MGLTileSet_Private.h in Headers */,
3593E5221D529C29006D9365 /* MGLStyleAttribute.h in Headers */,
DABFB8651CBE99E500D62B32 /* MGLOverlay.h in Headers */,
35E79F211D41266300957B9E /* MGLStyleLayer_Private.h in Headers */,
@@ -1857,6 +1876,7 @@
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */,
DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
3575798E1D502EC7000B822E /* MGLRuntimeStylingHelper.m in Sources */,
+ 4085AF091D933DEA00F11B22 /* MGLTileSetTests.mm in Sources */,
357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.m in Sources */,
357579871D502AFE000B822E /* MGLLineStyleLayerTests.m in Sources */,
357579891D502B06000B822E /* MGLCircleStyleLayerTests.m in Sources */,
@@ -1923,6 +1943,7 @@
DA88481F1CBAFA6200AB86E3 /* MGLMultiPoint.mm in Sources */,
DA88482B1CBAFA6200AB86E3 /* MGLTypes.m in Sources */,
4018B1C71CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
+ 404C26E41D89B877000AA13D /* MGLTileSet.mm in Sources */,
DA88481D1CBAFA6200AB86E3 /* MGLMapCamera.mm in Sources */,
DA8848261CBAFA6200AB86E3 /* MGLPolygon.mm in Sources */,
35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
@@ -1991,6 +2012,7 @@
DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */,
DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */,
DAA4E41E1CBB730400178DFB /* MGLMapCamera.mm in Sources */,
+ 404C26E51D89B877000AA13D /* MGLTileSet.mm in Sources */,
4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
DAA4E4341CBB730400178DFB /* MGLFaux3DUserLocationAnnotationView.m in Sources */,
35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 24925d169c..535e00e01e 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -56,3 +56,4 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[];
#import "NSValue+MGLStyleAttributeAdditions.h"
#import "NSString+MGLStyleAttributeAdditions.h"
#import "NSArray+MGLStyleAttributeAdditions.h"
+#import "MGLTileSet.h"
diff --git a/platform/ios/test/MGLTileSetTests.mm b/platform/ios/test/MGLTileSetTests.mm
new file mode 100644
index 0000000000..d77046928c
--- /dev/null
+++ b/platform/ios/test/MGLTileSetTests.mm
@@ -0,0 +1,82 @@
+#import <XCTest/XCTest.h>
+
+#import <Mapbox/Mapbox.h>
+#import "MGLTileSet_Private.h"
+
+#include <mbgl/util/tileset.hpp>
+
+@interface MGLTileSetTests : XCTestCase
+
+@end
+
+@implementation MGLTileSetTests
+
+- (void)testTileSet {
+ // a tile set that provides an mbgl tile set
+ MGLTileSet *tileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[@"tile.1",
+ @"tile.2",
+ @"tile.3"]];
+ mbgl::Tileset mbglTileset = [tileSet mbglTileset];
+
+ // has the correct URL templates
+ XCTAssertEqual(mbglTileset.tiles.size(), 3);
+ XCTAssertEqual(mbglTileset.tiles[0], "tile.1");
+ XCTAssertEqual(mbglTileset.tiles[1], "tile.2");
+ XCTAssertEqual(mbglTileset.tiles[2], "tile.3");
+
+ // has the default scheme
+ XCTAssertEqual(mbglTileset.scheme, mbgl::Tileset::Scheme::XYZ);
+
+ // when the tile set has no min or max zoom level set
+ tileSet.minimumZoomLevel = nil;
+ tileSet.maximumZoomLevel = nil;
+
+ // the mbgl object has default values for min and max zoom level
+ XCTAssertEqual([tileSet mbglTileset].zoomRange.min, 0);
+ XCTAssertEqual([tileSet mbglTileset].zoomRange.max, 22);
+
+ // when the tile set has min and/or max zoom level set
+ tileSet.minimumZoomLevel = @(1);
+ tileSet.maximumZoomLevel = @(2);
+
+ // the mbgl object reflects the set values for min and max zoom level
+ XCTAssertEqual([tileSet mbglTileset].zoomRange.min, 1);
+ XCTAssertEqual([tileSet mbglTileset].zoomRange.max, 2);
+
+ // when the tile set has an attribution
+ tileSet.attribution = @"my tileset © ©️🎈";
+
+ // the attribution is reflected by the mbgl tileset
+ XCTAssertEqual([tileSet mbglTileset].attribution, tileSet.attribution.UTF8String);
+
+ // when the scheme is changed
+ tileSet.scheme = MGLTileSetSchemeTMS;
+
+ // the scheme is reflected by the mbgl tileset
+ XCTAssertEqual([tileSet mbglTileset].scheme , mbgl::Tileset::Scheme::TMS);
+
+ // a tile set that provides an mbgl tile set and minimum and maximum zoom levels
+ tileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[@"tile.1"] minimumZoomLevel:15 maximumZoomLevel:20];
+
+ // the zoom levels are reflected by the mbgl tileset
+ XCTAssertEqual([tileSet mbglTileset].zoomRange.min, 15);
+ XCTAssertEqual([tileSet mbglTileset].zoomRange.max, 20);
+}
+
+- (void)testInvalidTileSet {
+ // a tile set that provides an mbgl tile set and invalid (crossed) minimum and maximum zoom levels throws an exception
+ XCTAssertThrowsSpecificNamed([[MGLTileSet alloc] initWithTileURLTemplates:@[@"tile.1"] minimumZoomLevel:10 maximumZoomLevel:9], NSException, @"Invalid minimumZoomLevel");
+
+ // a tile set that provides an mbgl tile set
+ MGLTileSet *tileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[@"tile.1"]];
+ tileSet.maximumZoomLevel = @(10);
+
+ // when the minimum zoom level is set higher than the maximum zoom level
+ XCTAssertThrowsSpecificNamed(tileSet.minimumZoomLevel = @(11), NSException, @"Invalid minimumZoomLevel");
+
+ // when the maximum zoom level is set lower than the minimum zoom level
+ tileSet.minimumZoomLevel = @(5);
+ XCTAssertThrowsSpecificNamed(tileSet.maximumZoomLevel = @(4), NSException, @"Invalid minimumZoomLevel");
+}
+
+@end