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

One of the common challenges customers face is efficiently managing multiple instances of MapView. Whether it's an app with various tabs each displaying a unique map, or different menus requiring individual map views, the key lies in handling these instances effectively without compromising on performance and user experience.

In this thread, we delve 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