summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-03-25 17:02:08 -0700
committerMinh Nguyễn <mxn@1ec5.org>2016-03-29 11:46:25 -0700
commita1e5701fa3fa7041cbbdd3edabd1c6a8006ce68b (patch)
tree4ad07a8c03277f4f9d4700ad27fd351ded166139
parentbbab5a5b5e9b3cd2461a1c088f8610e6f1938686 (diff)
downloadqtlocation-mapboxgl-a1e5701fa3fa7041cbbdd3edabd1c6a8006ce68b.tar.gz
[ios, osx] Centralized offline pack management
MGLOfflineStorage now maintains a centralized, strongly held, KVO-compliant collection of all extant offline packs. MGLOfflineStorage issues notifications for progress updates. Client code can now react to the successful addition of an offline pack either via the completion block or via a KVO insertion. Fixes #4287.
-rw-r--r--platform/darwin/include/MGLOfflinePack.h10
-rw-r--r--platform/darwin/include/MGLOfflineStorage.h36
-rw-r--r--platform/darwin/src/MGLOfflinePack_Private.h10
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm110
-rw-r--r--platform/ios/app/MBXOfflinePacksTableViewController.m110
5 files changed, 194 insertions, 82 deletions
diff --git a/platform/darwin/include/MGLOfflinePack.h b/platform/darwin/include/MGLOfflinePack.h
index d1f5a3ed53..fd8080523c 100644
--- a/platform/darwin/include/MGLOfflinePack.h
+++ b/platform/darwin/include/MGLOfflinePack.h
@@ -148,16 +148,6 @@ typedef struct MGLOfflinePackProgress {
*/
- (void)suspend;
-/**
- Request an asynchronous update to the pack’s `state` and `progress` properties.
-
- The state and progress of an inactive or completed pack are computed lazily. If
- you need the state or progress of a pack inside an
- `MGLOfflinePackListingCompletionHandler`, set the `delegate` property then call
- this method.
- */
-- (void)requestProgress;
-
@end
/**
diff --git a/platform/darwin/include/MGLOfflineStorage.h b/platform/darwin/include/MGLOfflineStorage.h
index 4f3432163b..931982dce3 100644
--- a/platform/darwin/include/MGLOfflineStorage.h
+++ b/platform/darwin/include/MGLOfflineStorage.h
@@ -7,6 +7,13 @@ NS_ASSUME_NONNULL_BEGIN
@class MGLOfflinePack;
@protocol MGLOfflineRegion;
+extern NSString * const MGLOfflinePackProgressChangedNotification;
+extern NSString * const MGLOfflinePackErrorNotification;
+extern NSString * const MGLOfflinePackMaximumMapboxTilesReachedNotification;
+
+extern NSString * const MGLOfflinePackErrorUserInfoKey;
+extern NSString * const MGLOfflinePackMaximumCountUserInfoKey;
+
/**
A block to be called once an offline pack has been completely created and
added.
@@ -29,16 +36,6 @@ typedef void (^MGLOfflinePackAdditionCompletionHandler)(MGLOfflinePack * _Nullab
typedef void (^MGLOfflinePackRemovalCompletionHandler)(NSError * _Nullable error);
/**
- A block to be called with a complete list of offline packs.
-
- @param pack Contains a pointer an array of packs, or `nil` if there was an
- error obtaining the packs.
- @param error Contains a pointer to an error object (if any) indicating why the
- list of packs could not be obtained.
- */
-typedef void (^MGLOfflinePackListingCompletionHandler)(NS_ARRAY_OF(MGLOfflinePack *) *packs, NSError * _Nullable error);
-
-/**
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.
@@ -50,7 +47,16 @@ typedef void (^MGLOfflinePackListingCompletionHandler)(NS_ARRAY_OF(MGLOfflinePac
*/
+ (instancetype)sharedOfflineStorage;
-- (instancetype)init NS_UNAVAILABLE;
+/**
+ An array of all known offline packs.
+
+ This property is set to `nil`, indicating that the receiver does not yet know
+ the existing packs, for an undefined amount of time starting from the moment
+ the shared offline storage object is initialized until the packs are fetched
+ from the database. After that point, this property is always non-nil, but it
+ may be empty to indicate that no packs are present.
+ */
+@property (nonatomic, copy, readonly, nullable) NS_ARRAY_OF(MGLOfflinePack *) *packs;
/**
Creates and registers an offline pack that downloads the resources needed to
@@ -85,14 +91,6 @@ typedef void (^MGLOfflinePackListingCompletionHandler)(NS_ARRAY_OF(MGLOfflinePac
- (void)removePack:(MGLOfflinePack *)pack withCompletionHandler:(nullable MGLOfflinePackRemovalCompletionHandler)completion;
/**
- Asynchronously calls a completion callback with all existing offline packs.
-
- @param completion The completion handler to call with the list of packs. This
- handler is executed asynchronously on the main queue.
- */
-- (void)getPacksWithCompletionHandler:(MGLOfflinePackListingCompletionHandler)completion;
-
-/**
Sets the maximum number of Mapbox-hosted tiles that may be downloaded and
stored on the current device.
diff --git a/platform/darwin/src/MGLOfflinePack_Private.h b/platform/darwin/src/MGLOfflinePack_Private.h
index e29018fc36..c1637ab4a8 100644
--- a/platform/darwin/src/MGLOfflinePack_Private.h
+++ b/platform/darwin/src/MGLOfflinePack_Private.h
@@ -11,6 +11,16 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithMBGLRegion:(mbgl::OfflineRegion *)region;
/**
+ Request an asynchronous update to the pack’s `state` and `progress` properties.
+
+ The state and progress of an inactive or completed pack are computed lazily. If
+ you need the state or progress of a pack inside an
+ `MGLOfflinePackListingCompletionHandler`, set the `delegate` property then call
+ this method.
+ */
+- (void)requestProgress;
+
+/**
Invalidates the pack and ensures that no future progress update can ever
revalidate it.
*/
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 4dbfb05801..2add5e1051 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -8,11 +8,30 @@
#include <mbgl/util/string.hpp>
-@interface MGLOfflineStorage ()
+static NSString * const MGLOfflineStorageFileName = @"cache.db";
+static NSString * const MGLOfflineStorageFileName3_2_0_beta_1 = @"offline.db";
-@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
+NSString * const MGLOfflinePackProgressChangedNotification = @"MGLOfflinePackProgressChanged";
+NSString * const MGLOfflinePackErrorNotification = @"MGLOfflinePackError";
+NSString * const MGLOfflinePackMaximumMapboxTilesReachedNotification = @"MGLOfflinePackMaximumMapboxTilesReached";
+
+NSString * const MGLOfflinePackErrorUserInfoKey = @"Error";
+NSString * const MGLOfflinePackMaximumCountUserInfoKey = @"MaximumCount";
+
+/**
+ A block to be called with a complete list of offline packs.
+
+ @param pack Contains a pointer an array of packs, or `nil` if there was an
+ error obtaining the packs.
+ @param error Contains a pointer to an error object (if any) indicating why the
+ list of packs could not be obtained.
+ */
+typedef void (^MGLOfflinePackListingCompletionHandler)(NS_ARRAY_OF(MGLOfflinePack *) *packs, NSError * _Nullable error);
+
+@interface MGLOfflineStorage () <MGLOfflinePackDelegate>
-- (instancetype)initWithFileName:(NSString *)fileName NS_DESIGNATED_INITIALIZER;
+@property (nonatomic, copy, readwrite) NS_MUTABLE_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
@end
@@ -22,14 +41,20 @@
static dispatch_once_t onceToken;
static MGLOfflineStorage *sharedOfflineStorage;
dispatch_once(&onceToken, ^{
- sharedOfflineStorage = [[self alloc] initWithFileName:@"cache.db"];
+ sharedOfflineStorage = [[self alloc] init];
+ [sharedOfflineStorage getPacksWithCompletionHandler:^(NS_ARRAY_OF(MGLOfflinePack *) *packs, __unused NSError *error) {
+ sharedOfflineStorage.packs = [packs mutableCopy];
+
+ for (MGLOfflinePack *pack in packs) {
+ pack.delegate = sharedOfflineStorage;
+ [pack requestProgress];
+ }
+ }];
});
return sharedOfflineStorage;
}
-// This method can’t be called -init, because that selector has been marked
-// unavailable in MGLOfflineStorage.h.
-- (instancetype)initWithFileName:(NSString *)fileName {
+- (instancetype)init {
if (self = [super init]) {
// Place the cache in a location specific to the application, so that
// packs downloaded by other applications don’t count toward this
@@ -46,7 +71,7 @@
withIntermediateDirectories:YES
attributes:nil
error:nil];
- NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:fileName];
+ NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:MGLOfflineStorageFileName];
NSString *cachePath = cacheURL ? cacheURL.path : @"";
// Avoid backing up the offline cache onto iCloud, because it can be
@@ -57,11 +82,10 @@
// Move the offline cache from v3.2.0-beta.1 to a location that can also
// be used for ambient caching.
- NSString *legacyCacheFileName = @"offline.db";
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
// ~/Documents/offline.db
NSArray *legacyPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *legacyCachePath = [legacyPaths.firstObject stringByAppendingPathComponent:legacyCacheFileName];
+ NSString *legacyCachePath = [legacyPaths.firstObject stringByAppendingPathComponent:MGLOfflineStorageFileName3_2_0_beta_1];
#elif TARGET_OS_MAC
// ~/Library/Caches/tld.app.bundle.id/offline.db
NSURL *legacyCacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
@@ -75,7 +99,7 @@
withIntermediateDirectories:YES
attributes:nil
error:nil];
- NSURL *legacyCacheURL = [legacyCacheDirectoryURL URLByAppendingPathComponent:legacyCacheFileName];
+ NSURL *legacyCacheURL = [legacyCacheDirectoryURL URLByAppendingPathComponent:MGLOfflineStorageLegacyFileName];
NSString *legacyCachePath = legacyCacheURL ? legacyCacheURL.path : @"";
#endif
if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath]) {
@@ -101,17 +125,52 @@
_mbglFileSource = nullptr;
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(__unused void *)context {
+#pragma mark KVO methods
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
// Synchronize the file source’s access token with the global one in MGLAccountManager.
if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) {
NSString *accessToken = change[NSKeyValueChangeNewKey];
if (![accessToken isKindOfClass:[NSNull class]]) {
self.mbglFileSource->setAccessToken(accessToken.UTF8String);
}
+ } else {
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
+- (void)insertPacks:(NSArray *)packs atIndexes:(NSIndexSet *)indices {
+ [(NSMutableArray *)self.packs insertObjects:packs atIndexes:indices];
+}
+
+- (void)addPacksObject:(MGLOfflinePack *)pack {
+ [(NSMutableArray *)self.packs addObject:pack];
+}
+
+- (void)removePacksAtIndexes:(NSIndexSet *)indices {
+ [(NSMutableArray *)self.packs removeObjectsAtIndexes:indices];
+}
+
+- (void)removePacksObject:(MGLOfflinePack *)pack {
+ [(NSMutableArray *)self.packs removeObject:pack];
+}
+
+#pragma mark Pack management methods
+
- (void)addPackForRegion:(id <MGLOfflineRegion>)region withContext:(NSData *)context completionHandler:(MGLOfflinePackAdditionCompletionHandler)completion {
+ __weak MGLOfflineStorage *weakSelf = self;
+ [self _addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) {
+ MGLOfflineStorage *strongSelf = weakSelf;
+ [strongSelf addPacksObject:pack];
+ pack.delegate = strongSelf;
+ [pack requestProgress];
+ if (completion) {
+ completion(pack, error);
+ }
+ }];
+}
+
+- (void)_addPackForRegion:(id <MGLOfflineRegion>)region withContext:(NSData *)context completionHandler:(MGLOfflinePackAdditionCompletionHandler)completion {
if (![region conformsToProtocol:@protocol(MGLOfflineRegion_Private)]) {
[NSException raise:@"Unsupported region type" format:
@"Regions of type %@ are unsupported.", NSStringFromClass([region class])];
@@ -139,6 +198,15 @@
}
- (void)removePack:(MGLOfflinePack *)pack withCompletionHandler:(MGLOfflinePackRemovalCompletionHandler)completion {
+ [self removePacksObject:pack];
+ [self _removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
+ if (completion) {
+ completion(error);
+ }
+ }];
+}
+
+- (void)_removePack:(MGLOfflinePack *)pack withCompletionHandler:(MGLOfflinePackRemovalCompletionHandler)completion {
mbgl::OfflineRegion *mbglOfflineRegion = pack.mbglOfflineRegion;
[pack invalidate];
self.mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) {
@@ -184,4 +252,22 @@
_mbglFileSource->setOfflineMapboxTileCountLimit(maximumCount);
}
+#pragma mark MGLOfflinePackDelegate methods
+
+- (void)offlinePack:(MGLOfflinePack *)pack progressDidChange:(__unused MGLOfflinePackProgress)progress {
+ [[NSNotificationCenter defaultCenter] postNotificationName:MGLOfflinePackProgressChangedNotification object:pack];
+}
+
+- (void)offlinePack:(MGLOfflinePack *)pack didReceiveError:(NSError *)error {
+ [[NSNotificationCenter defaultCenter] postNotificationName:MGLOfflinePackErrorNotification object:pack userInfo:@{
+ MGLOfflinePackErrorUserInfoKey: error,
+ }];
+}
+
+- (void)offlinePack:(MGLOfflinePack *)pack didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount {
+ [[NSNotificationCenter defaultCenter] postNotificationName:MGLOfflinePackMaximumMapboxTilesReachedNotification object:pack userInfo:@{
+ MGLOfflinePackMaximumCountUserInfoKey: @(maximumCount),
+ }];
+}
+
@end
diff --git a/platform/ios/app/MBXOfflinePacksTableViewController.m b/platform/ios/app/MBXOfflinePacksTableViewController.m
index fb9d5fb3ed..4f399d3d4f 100644
--- a/platform/ios/app/MBXOfflinePacksTableViewController.m
+++ b/platform/ios/app/MBXOfflinePacksTableViewController.m
@@ -28,12 +28,6 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
@end
-@interface MBXOfflinePacksTableViewController () <MGLOfflinePackDelegate>
-
-@property (nonatomic, strong) NS_MUTABLE_ARRAY_OF(MGLOfflinePack *) *offlinePacks;
-
-@end
-
@implementation MBXOfflinePacksTableViewController {
NSUInteger _untitledRegionCount;
}
@@ -41,25 +35,48 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)viewDidLoad {
[super viewDidLoad];
- __weak MBXOfflinePacksTableViewController *weakSelf = self;
- [[MGLOfflineStorage sharedOfflineStorage] getPacksWithCompletionHandler:^(NS_ARRAY_OF(MGLOfflinePack *) *packs, NSError *error) {
- MBXOfflinePacksTableViewController *strongSelf = weakSelf;
- strongSelf.offlinePacks = packs.mutableCopy;
- [strongSelf.tableView reloadData];
-
- for (MGLOfflinePack *pack in strongSelf.offlinePacks) {
- pack.delegate = strongSelf;
- [pack requestProgress];
- }
-
- if (error) {
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Can’t Find Offline Packs" message:@"Mapbox GL was unable to find the existing offline packs." preferredStyle:UIAlertControllerStyleAlert];
- [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
- [self presentViewController:alertController animated:YES completion:^{
- [strongSelf dismissViewControllerAnimated:YES completion:nil];
+ [[MGLOfflineStorage sharedOfflineStorage] addObserver:self forKeyPath:@"packs" options:NSKeyValueObservingOptionInitial context:NULL];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackProgressDidChange:) name:MGLOfflinePackProgressChangedNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveError:) name:MGLOfflinePackErrorNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveMaximumAllowedMapboxTiles:) name:MGLOfflinePackMaximumMapboxTilesReachedNotification object:nil];
+}
+
+- (void)dealloc {
+ [[MGLOfflineStorage sharedOfflineStorage] removeObserver:self forKeyPath:@"packs"];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
+ if ([keyPath isEqualToString:@"packs"]) {
+ NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
+ NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
+ NSMutableArray *indexPaths;
+ if (indices) {
+ indexPaths = [NSMutableArray arrayWithCapacity:indices.count];
+ [indices enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
+ [indexPaths addObject:[NSIndexPath indexPathForRow:idx inSection:0]];
}];
}
- }];
+ switch (changeKind) {
+ case NSKeyValueChangeInsertion:
+ [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
+ break;
+
+ case NSKeyValueChangeRemoval:
+ [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
+ break;
+
+ case NSKeyValueChangeReplacement:
+ [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
+ break;
+
+ default:
+ [self.tableView reloadData];
+ break;
+ }
+ } else {
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+ }
}
- (IBAction)addCurrentRegion:(id)sender {
@@ -89,13 +106,6 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Can’t Add Offline Pack" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
- } else {
- pack.delegate = strongSelf;
- [pack resume];
-
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:strongSelf.offlinePacks.count inSection:0];
- [strongSelf.offlinePacks addObject:pack];
- [strongSelf.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}];
}];
@@ -110,11 +120,11 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- return self.offlinePacks.count;
+ return [MGLOfflineStorage sharedOfflineStorage].packs.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- MGLOfflinePack *pack = self.offlinePacks[indexPath.row];
+ MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs[indexPath.row];
NSString *reuseIdentifier = pack.state == MGLOfflinePackStateActive ? MBXOfflinePacksTableViewActiveCellReuseIdentifier : MBXOfflinePacksTableViewInactiveCellReuseIdentifier;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath];
@@ -165,9 +175,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
- MGLOfflinePack *pack = self.offlinePacks[indexPath.row];
- [self.offlinePacks removeObjectAtIndex:indexPath.row];
- [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
+ MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs[indexPath.row];
[[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:nil];
}
}
@@ -177,7 +185,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
- MGLOfflinePack *pack = self.offlinePacks[indexPath.row];
+ MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs[indexPath.row];
switch (pack.state) {
case MGLOfflinePackStateUnknown:
break;
@@ -207,8 +215,11 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
#pragma mark - Offline pack delegate
-- (void)offlinePack:(MGLOfflinePack *)pack progressDidChange:(MGLOfflinePackProgress)progress {
- NSUInteger index = [self.offlinePacks indexOfObject:pack];
+- (void)offlinePackProgressDidChange:(NSNotification *)notification {
+ MGLOfflinePack *pack = notification.object;
+ NSAssert([pack isKindOfClass:[MGLOfflinePack class]], @"MGLOfflineStorage notification has a non-pack object.");
+
+ NSUInteger index = [[MGLOfflineStorage sharedOfflineStorage].packs indexOfObject:pack];
if (index == NSNotFound) {
return;
}
@@ -217,11 +228,28 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
-- (void)offlinePack:(MGLOfflinePack *)pack didReceiveError:(NSError *)error {
- NSLog(@"Offline pack “%@” received error: %@", pack.name, error.localizedFailureReason);
+- (void)offlinePackDidReceiveError:(NSNotification *)notification {
+ MGLOfflinePack *pack = notification.object;
+ NSAssert([pack isKindOfClass:[MGLOfflinePack class]], @"MGLOfflineStorage notification has a non-pack object.");
+
+ NSError *error = notification.userInfo[MGLOfflinePackErrorUserInfoKey];
+ NSAssert([error isKindOfClass:[NSError class]], @"MGLOfflineStorage notification has a non-error error.");
+
+ NSString *message = [NSString stringWithFormat:@"iosapp encountered an error while downloading the offline pack “%@”: %@", pack.name, error.localizedFailureReason];
+ if (error.code == MGLErrorCodeConnectionFailed) {
+ NSLog(@"%@", message);
+ } else {
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Error Downloading Offline Pack" message:message preferredStyle:UIAlertControllerStyleAlert];
+ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
+ [self presentViewController:alertController animated:YES completion:nil];
+ }
}
-- (void)offlinePack:(MGLOfflinePack *)pack didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount {
+- (void)offlinePackDidReceiveMaximumAllowedMapboxTiles:(NSNotification *)notification {
+ MGLOfflinePack *pack = notification.object;
+ NSAssert([pack isKindOfClass:[MGLOfflinePack class]], @"MGLOfflineStorage notification has a non-pack object.");
+
+ uint64_t maximumCount = [notification.userInfo[MGLOfflinePackMaximumCountUserInfoKey] unsignedLongLongValue];
NSLog(@"Offline pack “%@” reached limit of %llu tiles.", pack.name, maximumCount);
}