Best Practices for Managing Multiple MapView Instances in iOS Applications with HERE SDK

Symptoms
--------

Customers using multiple MapView instances in an iOS application may experience one or more of the following symptoms:

Increased memory consumption when switching between tabs or screens containing maps.
Slower application performance after repeatedly opening and closing map-based views.
Rendering issues when several map views are created simultaneously.
Maps taking longer to initialize when navigating between view controllers.
Unexpected resource usage caused by creating new MapView objects instead of reusing existing ones.
UI responsiveness degradation in applications that maintain multiple active maps.

Answer
------

For HERE SDK on iOS, the recommended approach is to reuse MapView instances whenever possible instead of creating a new instance each time a user navigates to a tab, menu, or view controller. A centralized manager that controls a shared MapView instance helps reduce memory usage, minimizes map initialization overhead, and improves overall application performance.

In this thread, we dive into the best practices for managing multiple MapView instances in iOS applications using the HERE SDK. By adhering to these guidelines, customers can ensure smooth, efficient, and resource-friendly map interactions within their applications.

1. Reuse MapView Instances: If possible, reuse MapView instances instead of creating a new one each time a tab or menu is revisited. Keep a reference to the initialized MapViews and show/hide them as needed.
2. Proper Disposal: When a MapView is no longer needed (e.g., when the user navigates away from a tab), properly dispose of it to free up resources. Make sure to also remove any listeners or callbacks attached to the MapView to prevent memory leaks.
3. MapRenderMode Configuration: We should use TEXTURE render mode for each MapView instance to avoid graphical issues that can arise with overlapping SurfaceViews in complex UIs.

We can create a centralized map manager. This manager will hold a single instance of the MapView and provide it to different view controllers. When a view controller is no longer visible, it will release the MapView, allowing it to be used by another controller. Here's how we can implement it:

1. MapViewManager.swift

This class will manage the MapView instance.

<br />import UIKitimport heresdkclass MapViewManager { static let shared = MapViewManager() private var mapView: MapView? private init() {} func getMapView(frame: CGRect) -> MapView { if mapView == nil { let mapViewOptions = MapViewOptions() mapViewOptions.renderMode = .texture mapView = MapView(frame: frame, mapViewOptions: mapViewOptions) // Initialize your map here } else { mapView?.frame = frame } return mapView! } func releaseMapView() { mapView?.onPause() // Optional, based on your app's behavior }}`<br />

2. TabOneViewController.swift and TabTwoViewController.swift

Both view controllers will request the MapView from MapViewManager

<br />class TabOneViewController: UIViewController { var mapView: MapView? override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if mapView == nil { mapView = MapViewManager.shared.getMapView(frame: view.bounds) view.addSubview(mapView!) } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if mapView != nil { mapView?.removeFromSuperview() // Remove the mapView MapViewManager.shared.releaseMapView() mapView = nil } }}`<br />

3. MainTabBarController.swift

This is the tab bar controller that will manager the tabs:

<br />import UIKitclass MainTabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() let tabOneVC = TabOneViewController() tabOneVC.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0) let tabTwoVC = TabTwoViewController() tabTwoVC.tabBarItem = UITabBarItem(tabBarSystemItem: .history, tag: 1) let controllers = [tabOneVC, tabTwoVC] self.viewControllers = controllers.map { UINavigationController(rootViewController: $0) } }}`<br />

Explanation:

• MapViewManager manages a single MapView instance. It creates the MapView on the first request and reuses it for subsequent requests.

• In TabOneViewController and TabTwoViewController, viewWillAppear gets the MapView from the manager and adds it to the view hierarchy. viewWillDisappear releases the MapView.

• By adding and removing the MapView in viewWillAppear and viewWillDisappear, we're effectively reusing the MapView across different tabs.

• releaseMapView in MapViewManager can be adjusted based on whether they want to pause map updates when it's not visible.

This approach ensures that only one MapView instance is alive at any time, reducing memory and resource usage. Additionally, it avoids issues with overlapping SurfaceViews by using TEXTURE render mode. More information on TEXTURE mode can be fetched from - https://www.here.com/docs/bundle/sdk-for-android-navigate-api-reference/page/com/here/sdk/mapview/MapRenderMode.html#SURFACE

Example Implementation Pattern
------------------------------

A recommended implementation includes:

1. A MapViewManager singleton that owns a single MapView.
2. View controllers obtaining the shared instance during viewWillAppear.
3. Removing the map from the view hierarchy during viewWillDisappear.
4. Releasing screen-specific observers and listeners during cleanup.
5. Using MapRenderMode.TEXTURE (or .texture in Swift) where applicable.

Product
-------

HERE SDK for iOS
Applicable to applications implementing multiple map-based screens, tabs, or view controllers

Keywords / Tags
---------------

HERE SDK, iOS MapView, multiple MapView instances, MapView reuse, memory optimization, MapViewManager, texture render mode, iOS map performance, map lifecycle, view controller navigation, rendering issues, resource management, Swift MapView, HERE maps, mobile application optimization


Did this page help you?