summaryrefslogtreecommitdiff
path: root/platform/darwin
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin')
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h87
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm106
-rw-r--r--platform/darwin/src/MGLTypes.h4
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm62
4 files changed, 246 insertions, 13 deletions
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index b48f2ebf2c..c6a51df80c 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -171,9 +171,9 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) {
/**
MGLOfflineStorage implements a singleton (shared object) that manages offline
- packs. All of this class’s instance methods are asynchronous, reflecting the
- fact that offline resources are stored in a database. The shared object
- maintains a canonical collection of offline packs in its `packs` property.
+ packs and ambient caching. All of this class’s instance methods are asynchronous,
+ reflecting the fact that offline resources are stored in a database. The shared
+ object maintains a canonical collection of offline packs in its `packs` property.
#### Related examples
See the <a href="https://docs.mapbox.com/ios/maps/examples/offline-pack/">
@@ -304,6 +304,21 @@ MGL_EXPORT
- (void)removePack:(MGLOfflinePack *)pack withCompletionHandler:(nullable MGLOfflinePackRemovalCompletionHandler)completion;
/**
+ Invalidates the specified offline pack. This method checks that the tiles
+ in the specified offline pack match those from the server. Local tiles that
+ do not match the latest version on the server are updated.
+
+ This is more efficient than deleting the offline pack and downloading it
+ again. If the data stored locally matches that on the server, new data will
+ not be downloaded.
+
+ @param pack The offline pack to be invalidated.
+ @param completion The completion handler to call once the pack has been
+ removed. This handler is executed asynchronously on the main queue.
+ */
+
+- (void)invalidatePack:(MGLOfflinePack *)pack withCompletionHandler:(void (^)(NSError * _Nullable))completion;
+/**
Forcibly, asynchronously reloads the `packs` property. At some point after this
method is called, the pointer values of the `MGLOfflinePack` objects in the
`packs` property change, even if the underlying data for these packs has not
@@ -341,6 +356,72 @@ MGL_EXPORT
*/
@property (nonatomic, readonly) unsigned long long countOfBytesCompleted;
+
+#pragma mark - Managing Ambient Cache
+
+/**
+ Sets the maximum ambient cache size in megabytes. The default maximum cache
+ size is 50 MB. To disable ambient caching, set the maximum ambient cache size
+ to `0`. Setting the maximum ambient cache size does not impact the maximum size
+ of offline packs.
+
+ While this method does not limit the space available to offline packs,
+ data in offline packs count towards this limit. If the maximum ambient
+ cache size is set to 30 MB and 20 MB of offline packs are downloaded,
+ there may be only 10 MB reserved for the ambient cache.
+
+ This method should be called before the map and map style have been loaded.
+
+ This method is potentially expensive, as the database will trim cached data
+ in order to prevent the ambient cache from being larger than the
+ specified amount.
+
+ @param cacheSize The maximum size in bytes for the ambient cache.
+ @param completion The completion handler to call once the maximum ambient cache size
+ has been set. This handler is executed synchronously on the main queue.
+ */
+
+- (void)setMaximumAmbientCacheSize:(NSUInteger)cacheSize withCompletionHandler:(void (^)(NSError *_Nullable error))completion;
+
+/**
+ Invalidates the ambient cache. This method checks that the tiles in the
+ ambient cache match those from the server. If the local tiles do not match
+ those on the server, they are re-downloaded.
+
+ This is recommended over clearing the cache or resetting the database
+ because valid local tiles will not be downloaded again.
+
+ Resources shared with offline packs will not be affected by this method.
+
+ @param completion The completion handler to call once the ambient cache has
+ been revalidated. This handler is executed asynchronously on the main queue.
+ */
+
+- (void)invalidateAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable error))completion;
+
+/**
+ Clears the ambient cache by deleting resources. This method does not
+ affect resources shared with offline regions.
+
+ @param completion The completion handler to call once resources from
+ the ambient cache have been cleared. This handler is executed
+ asynchronously on the main queue.
+ */
+
+- (void)clearAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable error))completion;
+
+/**
+ Deletes the existing database, which includes both the ambient cache and offline packs,
+ then reinitializes it.
+
+ You typically do not need to call this method.
+
+ @param completion The completion handler to call once the pack has database has
+ been reset. This handler is executed asynchronously on the main queue.
+ */
+
+- (void)resetDatabaseWithCompletionHandler:(void (^)(NSError *_Nullable error))completion;
+
/*
Inserts the provided resource into the ambient cache.
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 6effd8c3ce..93f986a518 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -48,7 +48,6 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
@property (nonatomic) std::shared_ptr<mbgl::DefaultFileSource> mbglFileSource;
@property (nonatomic) std::string mbglCachePath;
@property (nonatomic, getter=isPaused) BOOL paused;
-
@end
@implementation MGLOfflineStorage {
@@ -341,10 +340,11 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
NSMutableArray *packs;
if (!result) {
NSString *description = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"ADD_FILE_CONTENTS_FAILED_DESC", @"Foundation", nil, @"Unable to add offline packs from the file at %@.", @"User-friendly error description"), filePath];
- error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{
- NSLocalizedDescriptionKey: description,
- NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(result.error()).c_str())
- }];
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed
+ userInfo:@{
+ NSLocalizedDescriptionKey: description,
+ NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(result.error()).c_str())
+ }];
} else {
auto& regions = result.value();
packs = [NSMutableArray arrayWithCapacity:regions.size()];
@@ -401,7 +401,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
NSError *error;
if (!mbglOfflineRegion) {
NSString *errorDescription = @(mbgl::util::toString(mbglOfflineRegion.error()).c_str());
- error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:errorDescription ? @{
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:errorDescription ? @{
NSLocalizedDescriptionKey: errorDescription,
} : nil];
}
@@ -431,11 +431,10 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
completion(nil);
return;
}
-
_mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) {
NSError *error;
if (exception) {
- error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{
NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()),
}];
}
@@ -445,6 +444,29 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
});
}
});
+
+}
+
+- (void)invalidatePack:(MGLOfflinePack *)pack withCompletionHandler:(void (^)(NSError * _Nullable))completion {
+ mbgl::OfflineRegion& region = *pack.mbglOfflineRegion;
+ NSError *error;
+ if (!pack.mbglOfflineRegion) {
+ completion(nil);
+ return;
+ }
+
+ _mbglFileSource->invalidateOfflineRegion(region, [&](std::exception_ptr exception) {
+ if (exception) {
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{
+ NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()),
+ }];
+ }
+ });
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), [&, completion, error](void) {
+ completion(error);
+ });
+ }
}
- (void)reloadPacks {
@@ -462,7 +484,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
NSError *error;
NSMutableArray *packs;
if (!result) {
- error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:@{
NSLocalizedDescriptionKey: @(mbgl::util::toString(result.error()).c_str()),
}];
} else {
@@ -486,6 +508,72 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
_mbglFileSource->setOfflineMapboxTileCountLimit(maximumCount);
}
+#pragma mark - Ambient Cache management
+
+- (void)setMaximumAmbientCacheSize:(NSUInteger)cacheSize withCompletionHandler:(void (^)(NSError * _Nullable))completion {
+ _mbglFileSource->setMaximumAmbientCacheSize(cacheSize, [&, completion](std::exception_ptr exception) {
+ NSError *error;
+ if (completion) {
+ if (exception) {
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{
+ NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()),
+ }];
+ }
+ dispatch_sync(dispatch_get_main_queue(), ^ {
+ completion(error);
+ });
+ }
+ });
+}
+
+- (void)invalidateAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable))completion {
+ _mbglFileSource->invalidateAmbientCache([&, completion](std::exception_ptr exception){
+ NSError *error;
+ if (completion) {
+ if (exception) {
+ // Convert std::exception_ptr to an NSError.
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{
+ NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()),
+ }];
+ }
+ dispatch_async(dispatch_get_main_queue(), ^ {
+ completion(error);
+ });
+ }
+ });
+}
+
+- (void)clearAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable error))completion {
+ _mbglFileSource->clearAmbientCache([&, completion](std::exception_ptr exception){
+ NSError *error;
+ if (completion) {
+ if (exception) {
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{
+ NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()),
+ }];
+ }
+ dispatch_async(dispatch_get_main_queue(), [&, completion, error](void) {
+ completion(error);
+ });
+ }
+ });
+}
+
+- (void)resetDatabaseWithCompletionHandler:(void (^)(NSError *_Nullable error))completion {
+ _mbglFileSource->resetDatabase([&, completion](std::exception_ptr exception) {
+ NSError *error;
+ if (completion) {
+ if (exception) {
+ error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:@{
+ NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()),
+ }];
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(error);
+ });
+ }
+ });
+}
#pragma mark -
- (unsigned long long)countOfBytesCompleted {
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index b8354d2e83..7e0dd27141 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -53,7 +53,9 @@ typedef NS_ENUM(NSInteger, MGLErrorCode) {
/** Source is in use and cannot be removed */
MGLErrorCodeSourceIsInUseCannotRemove = 7,
/** Source is in use and cannot be removed */
- MGLErrorCodeSourceIdentifierMismatch = 8
+ MGLErrorCodeSourceIdentifierMismatch = 8,
+ /** An error occurred while modifying the offline storage database */
+ MGLErrorCodeModifyingOfflineStorageFailed = 9
};
/** Options for enabling debugging features in an `MGLMapView` instance. */
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm
index 5551d8889b..ee4bcc2c65 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.mm
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -201,6 +201,68 @@
pack = nil;
}
+- (void)testInvalidatePack {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Expect offline pack to be invalidated without an error."];
+ MGLCoordinateBounds bounds = {
+ { .latitude = 48.8660, .longitude = 2.3306 },
+ { .latitude = 48.8603, .longitude = 2.3213 },
+ };
+
+ NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
+ MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:styleURL bounds:bounds fromZoomLevel:10 toZoomLevel:11];
+
+ NSString *nameKey = @"Name";
+ NSString *name = @"Paris square";
+
+ NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{nameKey: name}];
+ [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) {
+ XCTAssertNotNil(pack);
+ [[MGLOfflineStorage sharedOfflineStorage] invalidatePack:pack withCompletionHandler:^(NSError * _Nullable) {
+ XCTAssertNotNil(pack);
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ }];
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+}
+
+- (void)testSetMaximumAmbientCache {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Expect maximum cache size to be raised without an error."];
+ [[MGLOfflineStorage sharedOfflineStorage] setMaximumAmbientCacheSize:0 withCompletionHandler:^(NSError * _Nullable error) {
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+}
+
+- (void)testInvalidateAmbientCache {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Expect cache to be invalidated without an error."];
+ [[MGLOfflineStorage sharedOfflineStorage] invalidateAmbientCacheWithCompletionHandler:^(NSError * _Nullable error) {
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+}
+
+- (void)testClearCache {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Expect cache to be cleared without an error."];
+ [[MGLOfflineStorage sharedOfflineStorage] clearAmbientCacheWithCompletionHandler:^(NSError * _Nullable error) {
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+}
+
+- (void)testResetDatabase {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Expect database to be reset without an error."];
+ [[MGLOfflineStorage sharedOfflineStorage] resetDatabaseWithCompletionHandler:^(NSError * _Nullable error) {
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+}
+
- (void)testBackupExclusion {
NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask