From 12e0a6b0c67bc2356dbe83d7ab19efdd9a3dc2ea Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Tue, 2 Jul 2019 16:33:09 -0700 Subject: [PATCH] [ios] Add removeStyleImage to MGLMapView (#14769) * [ios] Add shoulRremoveStyleImage to MGLMapViewDelegate. * [ios] Changelog update. * [ios, macos] Update shouldRemoveStyle method documentation. --- platform/ios/CHANGELOG.md | 4 ++++ platform/ios/src/MGLMapView+Impl.h | 1 + platform/ios/src/MGLMapView+Impl.mm | 5 +++++ platform/ios/src/MGLMapView.mm | 8 ++++++++ platform/ios/src/MGLMapViewDelegate.h | 14 ++++++++++++++ platform/ios/src/MGLMapView_Private.h | 1 + .../test/MGLMapViewDelegateIntegrationTests.swift | 2 ++ platform/macos/CHANGELOG.md | 1 + platform/macos/src/MGLMapView+Impl.h | 1 + platform/macos/src/MGLMapView+Impl.mm | 5 +++++ platform/macos/src/MGLMapView.mm | 8 ++++++++ platform/macos/src/MGLMapViewDelegate.h | 14 ++++++++++++++ platform/macos/src/MGLMapView_Private.h | 1 + .../test/MGLMapViewDelegateIntegrationTests.swift | 1 + 14 files changed, 66 insertions(+) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index dba3e2525d3..196c777a887 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -18,6 +18,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Removed previously deprecated methods and properties that had been marked `unavailable`. ([#15000](https://github.com/mapbox/mapbox-gl-native/pull/15000)) +### Styles and rendering + +* Added the `-[MGLMapViewDelegate mapView:shouldRemoveStyleImage:]` method for optimizing style image caching. ([#14769](https://github.com/mapbox/mapbox-gl-native/pull/14769)) + ### Other changes * Added variants of several animated `MGLMapView` methods that accept completion handlers ([#14381](https://github.com/mapbox/mapbox-gl-native/pull/14381)): diff --git a/platform/ios/src/MGLMapView+Impl.h b/platform/ios/src/MGLMapView+Impl.h index 3a7488b4438..0a62b7da821 100644 --- a/platform/ios/src/MGLMapView+Impl.h +++ b/platform/ios/src/MGLMapView+Impl.h @@ -69,6 +69,7 @@ class MGLMapViewImpl : public mbgl::MapObserver { void onSourceChanged(mbgl::style::Source& source) override; void onDidBecomeIdle() override; void onStyleImageMissing(const std::string& imageIdentifier) override; + bool onCanRemoveUnusedStyleImage(const std::string& imageIdentifier) override; protected: /// Cocoa map view that this adapter bridges to. diff --git a/platform/ios/src/MGLMapView+Impl.mm b/platform/ios/src/MGLMapView+Impl.mm index 73e692defe5..1bccfa662f0 100644 --- a/platform/ios/src/MGLMapView+Impl.mm +++ b/platform/ios/src/MGLMapView+Impl.mm @@ -100,3 +100,8 @@ NSString *imageName = [NSString stringWithUTF8String:imageIdentifier.c_str()]; [mapView didFailToLoadImage:imageName]; } + +bool MGLMapViewImpl::onCanRemoveUnusedStyleImage(const std::string &imageIdentifier) { + NSString *imageName = [NSString stringWithUTF8String:imageIdentifier.c_str()]; + return [mapView shouldRemoveStyleImage:imageName]; +} diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index ea4a482cccd..c0b73806079 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -6234,6 +6234,14 @@ - (void)didFailToLoadImage:(NSString *)imageName { } } +- (BOOL)shouldRemoveStyleImage:(NSString *)imageName { + if ([self.delegate respondsToSelector:@selector(mapView:shouldRemoveStyleImage:)]) { + return [self.delegate mapView:self shouldRemoveStyleImage:imageName]; + } + + return YES; +} + - (void)updateUserLocationAnnotationView { [self updateUserLocationAnnotationViewAnimatedWithDuration:0]; diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h index f5249d1797d..3ddb7b007f0 100644 --- a/platform/ios/src/MGLMapViewDelegate.h +++ b/platform/ios/src/MGLMapViewDelegate.h @@ -277,6 +277,20 @@ NS_ASSUME_NONNULL_BEGIN - (nullable UIImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName; +/** + Asks the delegate whether the map view should evict cached images. + + This method is called in two scenarios: when the cumulative size of unused images + exceeds the cache size or when the last tile that includes the image is removed from + memory. + + @param mapView The map view that is evicting the image. + @param imageName The image name that is going to be removed. + @return A Boolean value indicating whether the map view should evict + the cached image. + */ +- (BOOL)mapView:(MGLMapView *)mapView shouldRemoveStyleImage:(NSString *)imageName; + #pragma mark Tracking User Location /** diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h index 08c1ff410df..5aa4902a912 100644 --- a/platform/ios/src/MGLMapView_Private.h +++ b/platform/ios/src/MGLMapView_Private.h @@ -41,6 +41,7 @@ FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const _Nonnull MGLUnderlyingMapUna - (void)mapViewDidFinishLoadingStyle; - (void)sourceDidChange:(nonnull MGLSource *)source; - (void)didFailToLoadImage:(nonnull NSString *)imageName; +- (BOOL)shouldRemoveStyleImage:(nonnull NSString *)imageName; /** Triggers another render pass even when it is not necessary. */ - (void)setNeedsRerender; diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift index 1330281faa6..172538c65b7 100644 --- a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift +++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift @@ -98,4 +98,6 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate { func mapViewUserLocationAnchorPoint(_ mapView: MGLMapView) -> CGPoint { return CGPoint(x: 100, y: 100) } func mapView(_ mapView: MGLMapView, didFailToLoadImage imageName: String) -> UIImage? { return nil } + + func mapView(_ mapView: MGLMapView, shouldRemoveStyleImage imageName: String) -> Bool { return false } } diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 48a68d2e268..241499432b2 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -8,6 +8,7 @@ ### Styles and rendering * Setting `MGLMapView.contentInset` now moves the map’s focal point to the center of the content frame after insetting. ([#14664](https://github.com/mapbox/mapbox-gl-native/pull/14664)) +* Added the `-[MGLMapViewDelegate mapView:shouldRemoveStyleImage:]` method for optimizing style image caching. ([#14769](https://github.com/mapbox/mapbox-gl-native/pull/14769)) ### Other changes diff --git a/platform/macos/src/MGLMapView+Impl.h b/platform/macos/src/MGLMapView+Impl.h index 19583c17e50..2d523716d4c 100644 --- a/platform/macos/src/MGLMapView+Impl.h +++ b/platform/macos/src/MGLMapView+Impl.h @@ -36,6 +36,7 @@ class MGLMapViewImpl : public mbgl::MapObserver { void onDidFinishLoadingStyle() override; void onSourceChanged(mbgl::style::Source& source) override; void onDidBecomeIdle() override; + bool onCanRemoveUnusedStyleImage(const std::string& imageIdentifier) override; protected: /// Cocoa map view that this adapter bridges to. diff --git a/platform/macos/src/MGLMapView+Impl.mm b/platform/macos/src/MGLMapView+Impl.mm index 7be55456718..2354f67a6d5 100644 --- a/platform/macos/src/MGLMapView+Impl.mm +++ b/platform/macos/src/MGLMapView+Impl.mm @@ -94,3 +94,8 @@ MGLSource * nativeSource = [mapView.style sourceWithIdentifier:identifier]; [mapView sourceDidChange:nativeSource]; } + +bool MGLMapViewImpl::onCanRemoveUnusedStyleImage(const std::string &imageIdentifier) { + NSString *imageName = [NSString stringWithUTF8String:imageIdentifier.c_str()]; + return [mapView shouldRemoveStyleImage:imageName]; +} diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 75bdaac0804..3c9647571e0 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -978,6 +978,14 @@ - (void)sourceDidChange:(MGLSource *)source { self.needsDisplay = YES; } +- (BOOL)shouldRemoveStyleImage:(NSString *)imageName { + if ([self.delegate respondsToSelector:@selector(mapView:shouldRemoveStyleImage:)]) { + return [self.delegate mapView:self shouldRemoveStyleImage:imageName]; + } + + return YES; +} + #pragma mark Printing - (void)print:(__unused id)sender { diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h index 1de4b47eb7e..098164cd759 100644 --- a/platform/macos/src/MGLMapViewDelegate.h +++ b/platform/macos/src/MGLMapViewDelegate.h @@ -183,6 +183,20 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName; +/** + Asks the delegate whether the map view should evict cached images. + + This method is called in two scenarios: when the cumulative size of unused images + exceeds the cache size or when the last tile that includes the image is removed from + memory. + + @param mapView The map view that is evicting the image. + @param imageName The image name that is going to be removed. + @return A Boolean value indicating whether the map view should evict + the cached image. + */ +- (BOOL)mapView:(MGLMapView *)mapView shouldRemoveStyleImage:(NSString *)imageName; + #pragma mark Managing the Appearance of Annotations /** diff --git a/platform/macos/src/MGLMapView_Private.h b/platform/macos/src/MGLMapView_Private.h index afd7cf2422b..3d9b36c30ab 100644 --- a/platform/macos/src/MGLMapView_Private.h +++ b/platform/macos/src/MGLMapView_Private.h @@ -45,6 +45,7 @@ namespace mbgl { - (void)mapViewDidBecomeIdle; - (void)mapViewDidFinishLoadingStyle; - (void)sourceDidChange:(nonnull MGLSource *)source; +- (BOOL)shouldRemoveStyleImage:(nonnull NSString *)imageName; /// Asynchronously render a frame of the map. - (void)setNeedsRerender; diff --git a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift index 6c37017be69..90a777e379e 100644 --- a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift +++ b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift @@ -59,4 +59,5 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate { func mapView(_ mapView: MGLMapView, calloutViewControllerFor annotation: MGLAnnotation) -> NSViewController? { return nil } + func mapView(_ mapView: MGLMapView, shouldRemoveStyleImage imageName: String) -> Bool { return false } }