diff options
author | Jason Wray <jason@mapbox.com> | 2018-07-16 12:19:18 -0400 |
---|---|---|
committer | Jason Wray <jason@mapbox.com> | 2018-11-27 14:39:29 -0500 |
commit | c7f9f1582f39115e3b05c89e8c253f258515f112 (patch) | |
tree | f05e04f2e6dab74d01c688dccd29571fda5198f8 /platform | |
parent | f772a6392db1f24a8fbfd0a120de87fd96e51921 (diff) | |
download | qtlocation-mapboxgl-c7f9f1582f39115e3b05c89e8c253f258515f112.tar.gz |
[ios] Add frame duration graph view to iosapp
Diffstat (limited to 'platform')
-rw-r--r-- | platform/ios/app/MBXFrameTimeGraphView.h | 11 | ||||
-rw-r--r-- | platform/ios/app/MBXFrameTimeGraphView.m | 140 | ||||
-rw-r--r-- | platform/ios/app/MBXViewController.m | 23 | ||||
-rw-r--r-- | platform/ios/app/Main.storyboard | 27 | ||||
-rw-r--r-- | platform/ios/ios.xcodeproj/project.pbxproj | 6 |
5 files changed, 198 insertions, 9 deletions
diff --git a/platform/ios/app/MBXFrameTimeGraphView.h b/platform/ios/app/MBXFrameTimeGraphView.h new file mode 100644 index 0000000000..9c3f6f8c32 --- /dev/null +++ b/platform/ios/app/MBXFrameTimeGraphView.h @@ -0,0 +1,11 @@ +#import <UIKit/UIKit.h> + +NS_ASSUME_NONNULL_BEGIN + +@interface MBXFrameTimeGraphView : UIView + +- (void)updatePathWithFrameDuration:(CFTimeInterval)frameDuration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/app/MBXFrameTimeGraphView.m b/platform/ios/app/MBXFrameTimeGraphView.m new file mode 100644 index 0000000000..f689768818 --- /dev/null +++ b/platform/ios/app/MBXFrameTimeGraphView.m @@ -0,0 +1,140 @@ +#import "MBXFrameTimeGraphView.h" + +const CGFloat MBXFrameTimeExaggeration = 4.f * 1000.f; +const CGFloat MBXFrameTimeBarWidth = 4.f; + +@interface MBXFrameTimeGraphView () + +@property (nonatomic) CAScrollLayer *scrollLayer; +@property (nonatomic) CAShapeLayer *thresholdLayer; +@property (nonatomic) CGFloat currentX; +@property (nonatomic) NSMutableArray<CAShapeLayer *> *barLayers; + +@property (nonatomic) UIColor *safeColor; +@property (nonatomic) UIColor *warningColor; +@property (nonatomic) UIColor *dangerColor; + +@end + +@implementation MBXFrameTimeGraphView + +- (instancetype)init { + if (self = [super init]) { + [self commonInit]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + if (self = [super initWithCoder:aDecoder]) { + [self commonInit]; + } + return self; +} + +- (void)commonInit { + self.userInteractionEnabled = NO; + self.layer.opacity = 0.9f; + + self.scrollLayer = [CAScrollLayer layer]; + self.scrollLayer.scrollMode = kCAScrollHorizontally; + self.scrollLayer.masksToBounds = YES; + [self.layer addSublayer:self.scrollLayer]; + + self.thresholdLayer = [CAShapeLayer layer]; + self.thresholdLayer.fillColor = [UIColor darkGrayColor].CGColor; + [self.layer addSublayer:self.thresholdLayer]; + + self.barLayers = [NSMutableArray array]; + + self.safeColor = [UIColor colorWithRed:(CGFloat)(0.f/255.f) green:(CGFloat)(190.f/255.f) blue:(CGFloat)(123.f/255.f) alpha:1.f]; + self.warningColor = [UIColor colorWithRed:(CGFloat)(255.f/255.f) green:(CGFloat)(154.f/255.f) blue:(CGFloat)(82.f/255.f) alpha:1.f]; + self.dangerColor = [UIColor colorWithRed:(CGFloat)(255.f/255.f) green:(CGFloat)(91.f/255.f) blue:(CGFloat)(86.f/255.f) alpha:1.f]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + if (!CGRectEqualToRect(self.scrollLayer.frame, self.bounds)) { + self.scrollLayer.frame = self.bounds; + + CGRect thresholdLineRect = CGRectMake(0, self.frame.size.height - [self renderDurationTargetMilliseconds], self.frame.size.width, 1); + self.thresholdLayer.path = CGPathCreateWithRect(thresholdLineRect, nil); + } +} + +- (void)updatePathWithFrameDuration:(CFTimeInterval)frameDuration { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + + self.currentX += MBXFrameTimeBarWidth; + + CAShapeLayer *bar = [self barWithFrameDuration:frameDuration]; + bar.position = CGPointMake(self.currentX, self.frame.size.height); + + [self.scrollLayer addSublayer:bar]; + [self.barLayers addObject:bar]; + + [self.scrollLayer scrollToPoint:CGPointMake(self.currentX - self.frame.size.width, 0)]; + + [self removeStaleBars]; + + [CATransaction commit]; +} + +- (CGFloat)renderDurationTargetMilliseconds { + CGFloat maximumFramesPerSecond; + if (@available(iOS 10.3, *)) { + maximumFramesPerSecond = UIScreen.mainScreen.maximumFramesPerSecond; + } else { + // Not always strictly accurate, but works as an expedient approximation. + maximumFramesPerSecond = 60; + } + + CGFloat target = (1.0 / maximumFramesPerSecond) * MBXFrameTimeExaggeration; + return [self roundedFloat:target]; +} + +- (CGFloat)roundedFloat:(CGFloat)f { +#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + CGFloat scaleFactor = [UIScreen mainScreen].nativeScale; +#elif TARGET_OS_MAC + CGFloat scaleFactor = [NSScreen mainScreen].backingScaleFactor; +#endif + return round(f * scaleFactor) / scaleFactor; +} + +- (CAShapeLayer *)barWithFrameDuration:(CFTimeInterval)frameDuration { + CAShapeLayer *bar = [CAShapeLayer layer]; + + CGRect barRect = CGRectMake(0, 0, MBXFrameTimeBarWidth, -(fminf(frameDuration * MBXFrameTimeExaggeration, self.frame.size.height))); + UIBezierPath *barPath = [UIBezierPath bezierPathWithRect:barRect]; + bar.path = barPath.CGPath; + bar.fillColor = [self colorForFrameDuration:frameDuration].CGColor; + + return bar; +} + +- (UIColor *)colorForFrameDuration:(CFTimeInterval)frameDuration { + CGFloat renderDurationTargetMilliseconds = [self renderDurationTargetMilliseconds]; + frameDuration *= MBXFrameTimeExaggeration; + + if (frameDuration < renderDurationTargetMilliseconds && frameDuration > (renderDurationTargetMilliseconds * 0.75)) { + return self.warningColor; + } else if (frameDuration > renderDurationTargetMilliseconds) { + return self.dangerColor; + } else { + return self.safeColor; + } +} + +- (void)removeStaleBars { + if (self.barLayers.count > (self.frame.size.width / MBXFrameTimeBarWidth * 3)) { + NSRange staleBarsRange = NSMakeRange(0, self.frame.size.width / MBXFrameTimeBarWidth); + NSArray *staleBars = [self.barLayers subarrayWithRange:staleBarsRange]; + [staleBars makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; + [self.barLayers removeObjectsInRange:staleBarsRange]; + } +} + +@end diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index f058b75dc9..856e4de481 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -8,6 +8,8 @@ #import "LimeGreenStyleLayer.h" #import "MBXEmbeddedMapViewController.h" +#import "MBXFrameTimeGraphView.h" + #import <Mapbox/Mapbox.h> #import "../src/MGLMapView_Experimental.h" @@ -95,6 +97,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { MBXSettingsMiscellaneousWorldTour, MBXSettingsMiscellaneousRandomTour, MBXSettingsMiscellaneousShowZoomLevel, + MBXSettingsMiscellaneousShowFrameTimeGraph, MBXSettingsMiscellaneousScrollView, MBXSettingsMiscellaneousToggleTwoMaps, MBXSettingsMiscellaneousLocalizeLabels, @@ -192,14 +195,17 @@ CLLocationCoordinate2D randomWorldCoordinate() { @property (nonatomic) IBOutlet MGLMapView *mapView; @property (weak, nonatomic) IBOutlet UIButton *hudLabel; +@property (weak, nonatomic) IBOutlet MBXFrameTimeGraphView *frameTimeGraphView; @property (nonatomic) NSInteger styleIndex; @property (nonatomic) BOOL debugLoggingEnabled; @property (nonatomic) BOOL customUserLocationAnnnotationEnabled; @property (nonatomic, getter=isLocalizingLabels) BOOL localizingLabels; @property (nonatomic) BOOL reuseQueueStatsEnabled; @property (nonatomic) BOOL mapInfoHUDEnabled; +@property (nonatomic) BOOL frameTimeGraphEnabled; @property (nonatomic) BOOL shouldLimitCameraChanges; @property (nonatomic) BOOL randomWalk; + @end @interface MGLMapView (MBXViewController) @@ -238,6 +244,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]; self.mapView.showsScale = YES; self.mapView.showsUserHeadingIndicator = YES; + self.mapView.experimental_enableFrameRateMeasurement = YES; self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular]; if ([MGLAccountManager accessToken].length) @@ -293,6 +300,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { [defaults setBool:self.mapView.showsUserLocation forKey:@"MBXShowsUserLocation"]; [defaults setInteger:self.mapView.debugMask forKey:@"MBXDebugMask"]; [defaults setBool:self.mapInfoHUDEnabled forKey:@"MBXShowsZoomLevelHUD"]; + [defaults setBool:self.mapInfoHUDEnabled forKey:@"MBXShowsFrameTimeGraph"]; [defaults synchronize]; } @@ -323,6 +331,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { self.mapInfoHUDEnabled = YES; [self updateHUD]; } + self.frameTimeGraphEnabled = [defaults boolForKey:@"MBXShowsFrameTimeGraph"]; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations @@ -452,6 +461,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { @"Start World Tour", @"Random Tour", [NSString stringWithFormat:@"%@ Map Info HUD", (_mapInfoHUDEnabled ? @"Hide" :@"Show")], + [NSString stringWithFormat:@"%@ Frame Time Graph", (_frameTimeGraphEnabled ? @"Hide" :@"Show")], @"Embedded Map View", [NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")], [NSString stringWithFormat:@"Show Labels in %@", (_localizingLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])], @@ -681,6 +691,12 @@ CLLocationCoordinate2D randomWorldCoordinate() { [self updateHUD]; break; } + case MBXSettingsMiscellaneousShowFrameTimeGraph: + { + self.frameTimeGraphEnabled = !self.frameTimeGraphEnabled; + self.frameTimeGraphView.hidden = !self.frameTimeGraphEnabled; + break; + } case MBXSettingsMiscellaneousScrollView: { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; @@ -2224,7 +2240,6 @@ CLLocationCoordinate2D randomWorldCoordinate() { } hudString = [NSString stringWithFormat:@"Visible: %ld Queued: %ld", (unsigned long)self.mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations]; } else if (self.mapInfoHUDEnabled) { - if (!self.mapView.experimental_enableFrameRateMeasurement) self.mapView.experimental_enableFrameRateMeasurement = YES; hudString = [NSString stringWithFormat:@"%.f FPS (%.1fms) ∕ %.2f ∕ ↕\U0000FE0E%.f° ∕ %.f°", roundf(self.mapView.averageFrameRate), self.mapView.averageFrameTime, self.mapView.zoomLevel, self.mapView.camera.pitch, self.mapView.direction]; @@ -2281,4 +2296,10 @@ CLLocationCoordinate2D randomWorldCoordinate() { return features; } +- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered { + if (self.frameTimeGraphEnabled) { + [self.frameTimeGraphView updatePathWithFrameDuration:mapView.frameTime]; + } +} + @end diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard index 3e8a0ad02a..f4e535a56c 100644 --- a/platform/ios/app/Main.storyboard +++ b/platform/ios/app/Main.storyboard @@ -1,14 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff"> +<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> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/> - <capability name="Constraints to layout margins" minToolsVersion="6.0"/> - <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/> - <capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> @@ -42,12 +39,25 @@ </userDefinedRuntimeAttribute> </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"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <accessibility key="accessibilityConfiguration"> + <accessibilityTraits key="traits" notEnabled="YES"/> + </accessibility> + <constraints> + <constraint firstAttribute="height" constant="200" id="TgT-yb-9e5"/> + </constraints> + </view> </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <gestureRecognizers/> <constraints> <constraint firstItem="58y-pX-YyB" firstAttribute="top" secondItem="kNe-zV-9ha" secondAttribute="topMargin" constant="30" id="89S-qk-mPR"/> + <constraint firstItem="BHE-Wn-x69" firstAttribute="leading" secondItem="kNe-zV-9ha" secondAttribute="leading" id="aHd-3F-9nV"/> + <constraint firstAttribute="bottom" secondItem="BHE-Wn-x69" secondAttribute="bottom" id="bfH-4q-2uU"/> <constraint firstItem="58y-pX-YyB" firstAttribute="leading" secondItem="kNe-zV-9ha" secondAttribute="leadingMargin" id="cXU-Qh-ilW"/> + <constraint firstAttribute="trailing" secondItem="BHE-Wn-x69" secondAttribute="trailing" id="lZL-gi-2XC"/> <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="58y-pX-YyB" secondAttribute="trailing" id="txU-Gp-2du"/> </constraints> <connections> @@ -104,6 +114,7 @@ </rightBarButtonItems> </navigationItem> <connections> + <outlet property="frameTimeGraphView" destination="BHE-Wn-x69" id="sFg-9b-DgH"/> <outlet property="hudLabel" destination="58y-pX-YyB" id="aGG-7a-bZR"/> <outlet property="mapView" destination="kNe-zV-9ha" id="VNR-WO-1q4"/> <segue destination="zvf-Qd-4Ru" kind="show" identifier="ShowSnapshots" id="hzX-Jp-UJq"/> @@ -117,7 +128,7 @@ </connections> </pongPressGestureRecognizer> </objects> - <point key="canvasLocation" x="1365.5999999999999" y="349.13793103448279"/> + <point key="canvasLocation" x="1365.5999999999999" y="348.57571214392806"/> </scene> <!--Offline Packs--> <scene sceneID="xIg-PA-7r3"> @@ -279,7 +290,7 @@ </connections> </switch> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Rotation" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vio-XU-tgS"> - <rect key="frame" x="209.5" y="6" width="50.5" height="16"/> + <rect key="frame" x="209" y="6" width="50.5" height="16"/> <constraints> <constraint firstAttribute="width" constant="50.5" id="OiV-2P-9xm"/> </constraints> @@ -294,7 +305,7 @@ </connections> </switch> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pitch" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0uK-zq-Ys2"> - <rect key="frame" x="312" y="6" width="31" height="16"/> + <rect key="frame" x="312.5" y="6" width="31" height="16"/> <constraints> <constraint firstAttribute="width" constant="31" id="gM8-I7-4d3"/> </constraints> diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index f0ddbb346d..160d82bcf9 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -359,6 +359,7 @@ 9654C1261FFC1AB900DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */; }; 9654C1291FFC1CCD00DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1271FFC1CC000DB6A19 /* MGLPolygon_Private.h */; }; 9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */; }; + 965DF51120F9430500438AAC /* MBXFrameTimeGraphView.m in Sources */ = {isa = PBXBuildFile; fileRef = 965DF51020F9430500438AAC /* MBXFrameTimeGraphView.m */; }; 966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */; }; 966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; }; 966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; }; @@ -1047,6 +1048,8 @@ 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolyline_Private.h; sourceTree = "<group>"; }; 9654C1271FFC1CC000DB6A19 /* MGLPolygon_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolygon_Private.h; sourceTree = "<group>"; }; 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewScaleBarTests.m; sourceTree = "<group>"; }; + 965DF50F20F9430500438AAC /* MBXFrameTimeGraphView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXFrameTimeGraphView.h; sourceTree = "<group>"; }; + 965DF51020F9430500438AAC /* MBXFrameTimeGraphView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBXFrameTimeGraphView.m; sourceTree = "<group>"; }; 9660916B1E5BBFD700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; }; 9660916C1E5BBFD900A9A03B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; }; 9660916D1E5BBFDB00A9A03B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; }; @@ -1875,6 +1878,8 @@ 1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */, DA1DC9531CB6C1C2006E619F /* MBXViewController.h */, DA1DC99A1CB6E064006E619F /* MBXViewController.m */, + 965DF50F20F9430500438AAC /* MBXFrameTimeGraphView.h */, + 965DF51020F9430500438AAC /* MBXFrameTimeGraphView.m */, 632281DD1E6F855900D75A5D /* MBXEmbeddedMapViewController.h */, 632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */, DA821D051CCC6D59007508D4 /* Main.storyboard */, @@ -2952,6 +2957,7 @@ files = ( DA1DC9971CB6E046006E619F /* main.m in Sources */, 354B839C1D2E9B48005D9406 /* MBXUserLocationAnnotationView.m in Sources */, + 965DF51120F9430500438AAC /* MBXFrameTimeGraphView.m in Sources */, DA1DC9991CB6E054006E619F /* MBXAppDelegate.m in Sources */, DA1DC96B1CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m in Sources */, DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */, |