[ios] Cache Management API (#14978)
This commit is contained in:
@@ -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/">
|
||||
@@ -303,6 +303,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
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -128,6 +128,19 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)invalidatePacks:(id)sender {
|
||||
for (MGLOfflinePack *pack in [MGLOfflineStorage sharedOfflineStorage].packs) {
|
||||
|
||||
CFTimeInterval start = CACurrentMediaTime();
|
||||
[[MGLOfflineStorage sharedOfflineStorage] invalidatePack:pack withCompletionHandler:^(NSError * _Nullable error) {
|
||||
CFTimeInterval end = CACurrentMediaTime();
|
||||
CFTimeInterval difference = end - start;
|
||||
NSLog(@"invalidatePack Started: %f Ended: %f Total Time: %f", start, end, difference);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14810.11" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -15,14 +13,14 @@
|
||||
<objects>
|
||||
<viewController id="WaX-pd-UZQ" userLabel="Map View Controller" customClass="MBXViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Z9X-fc-PUC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="203" height="33"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="203" height="33"/>
|
||||
<subviews>
|
||||
<button hidden="YES" opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
|
||||
<rect key="frame" x="8" y="102" width="40" height="20"/>
|
||||
<rect key="frame" x="8" y="82" width="40" height="20"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" button="YES" notEnabled="YES"/>
|
||||
@@ -40,7 +38,7 @@
|
||||
</userDefinedRuntimeAttributes>
|
||||
</button>
|
||||
<view hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BHE-Wn-x69" customClass="MBXFrameTimeGraphView">
|
||||
<rect key="frame" x="0.0" y="467" width="375" height="200"/>
|
||||
<rect key="frame" x="0.0" y="-167" width="203" height="200"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" notEnabled="YES"/>
|
||||
@@ -143,7 +141,7 @@
|
||||
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fGu-Ys-Eh1" id="sUf-bc-8xG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Inactive Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JtH-Ce-MI5">
|
||||
@@ -167,7 +165,7 @@
|
||||
<rect key="frame" x="0.0" y="72" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mKB-tz-Zfl" id="nS3-aU-nBr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Active Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9ZK-gS-wJ4">
|
||||
@@ -194,11 +192,18 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Offline Packs" id="UcK-PK-eQA">
|
||||
<barButtonItem key="rightBarButtonItem" systemItem="add" id="gCV-hl-Mzc">
|
||||
<connections>
|
||||
<action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem systemItem="add" id="gCV-hl-Mzc">
|
||||
<connections>
|
||||
<action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem style="plain" systemItem="refresh" id="2fx-iS-Veb">
|
||||
<connections>
|
||||
<action selector="invalidatePacks:" destination="7q0-lI-zqb" id="5lx-FY-aTt"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</rightBarButtonItems>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<segue destination="x2D-ga-sM5" kind="unwind" identifier="ReturnToMap" unwindAction="unwindToMapViewController:" id="6MZ-Ed-tu2"/>
|
||||
@@ -215,7 +220,7 @@
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="PSe-Ot-7Ff" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="ONr-CS-J5X">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
@@ -257,7 +262,7 @@
|
||||
</constraints>
|
||||
</scrollView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="l5l-w7-P80" userLabel="Control Panel View">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="64"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="64"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Zoom" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DgB-BD-Ltx">
|
||||
<rect key="frame" x="29.5" y="6" width="35" height="16"/>
|
||||
@@ -381,22 +386,22 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="miZ-Fw-EWq" userLabel="Image View TL">
|
||||
<rect key="frame" x="0.0" y="64" width="125" height="301.5"/>
|
||||
<rect key="frame" x="0.0" y="44" width="125" height="311.5"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="XuN-T4-Z83" userLabel="Image View TM">
|
||||
<rect key="frame" x="125" y="64" width="125" height="301.5"/>
|
||||
<rect key="frame" x="125" y="44" width="125" height="311.5"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ykR-Ku-i9l" userLabel="Image View TR">
|
||||
<rect key="frame" x="250" y="64" width="125" height="301.5"/>
|
||||
<rect key="frame" x="250" y="44" width="125" height="311.5"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TL0-V8-T2F" userLabel="Image View BL">
|
||||
<rect key="frame" x="0.0" y="365.5" width="125" height="301.5"/>
|
||||
<rect key="frame" x="0.0" y="355.5" width="125" height="311.5"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="eMy-JU-rq4" userLabel="Image View BM">
|
||||
<rect key="frame" x="125" y="365.5" width="125" height="301.5"/>
|
||||
<rect key="frame" x="125" y="355.5" width="125" height="311.5"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zT0-3J-0xw" userLabel="Image View BR">
|
||||
<rect key="frame" x="250" y="365.5" width="125" height="301.5"/>
|
||||
<rect key="frame" x="250" y="355.5" width="125" height="311.5"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
||||
Reference in New Issue
Block a user