5

I have followed the advice available in several SO questions, like this one, in order to release MKMapView from memory - my code below

- (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; self.map.mapType = MKMapTypeHybrid; self.map.showsUserLocation = NO; self.map.delegate = nil; [self.map removeFromSuperview]; self.map = nil; self.locationManager.delegate = nil; } 

In part, it works, but not entirely. Let me provide some data.

Below is the memory allocation recording from Instruments.

enter image description here

The two red flags (Generations) indicate the states before I displayed MKMapViewin a modal view controller and after I have dismissed it. MKMapView seems to get deallocated. For instance, if I filter Statistics stack in Instruments for MKMapView, the object does indeed appear when the modal view is presented, and disappears once it's closed. However, having dismissed the map view, I still have 30+ MB of memory that has not been freed up.

Generation B (second red flag) data shows that there is a large number of objects (and non-objects) that are holding this memory.

enter image description here

When I look at extended details of one of those instances, it usually shows a stack trace that features private classes that, I guess, are related to map drawing enter image description here

Does anyone know how to free up all that data? Is there some cache I could/should clean?

4
  • have you managed to solve this issue ? Commented Mar 10, 2015 at 13:13
  • Unfortunately, not yet.. Commented Mar 10, 2015 at 17:31
  • Any luck now in clearing the memory? Commented Dec 18, 2015 at 2:20
  • Alas. At one point I also set the self.locationManager to nil and it seemed to have helped, but it didn't - the memory is still allocated. Commented Dec 18, 2015 at 9:03

2 Answers 2

1

In my app, which uses the map view controller under control of a tab view controller, I store a reference to a MKMapView in a static variable and use this same map view over and over again instead of allocating a new one in ViewDidLoad every time. My (partial) code:

@implementation PubMapViewController { NSMutableArray *annotations; } static MKMapView *_mapView = nil; - (void)viewDidLoad { [super viewDidLoad]; if (!_mapView) { _mapView = [[MKMapView alloc] init]; // frame set up with constraints } else { [_mapView removeAnnotations:_mapView.annotations]; // precaution } [_mapViewProxy addSubview:_mapView]; [self addConstraints:_mapView]; [self configureView:((PubTabBarController *)self.tabBarController).detailItem]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [_mapView addAnnotations:annotations]; if (annotations.count == 1) { [_mapView selectAnnotation:annotations[0] animated:YES]; } } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [_mapView removeAnnotations:_mapView.annotations]; } 

Here, configureView: sets up the map for self.tabBarController.detailItem, sets its delegate and stores the map annotations in variable annotations.

The map is made a subview to a view defined in the interface builder (instance variable @property (weak, nonatomic) IBOutlet UIView *mapViewProxy;). The map must obtain the same size as mapViewProxy, and as I use autolayout, the frame size of _mapView is controlled entirely using the constraints set up in addConstraints (top, bottom, left, and right equal to _mapView.superview).

I found it compulsory to remove the annotations from the map in viewDidDisppear: and to add them back in viewDidAppear. It might be even more clean to unset _mapView.delegate in viewDidDisppear: and set it back in viewDidAppear.

BTW: The static variable _mapView still misleadingly carries the leading underscore since it was an instance variable before set up by defining the MKMapView in IB.

Sign up to request clarification or add additional context in comments.

Comments

0

This is the solution that I used and it is working fine. I think this problem was only introduced recently because I haven't had issues with the Map deallocating properly before within the same project.

I stored the map instance within a singleton and simply check for it's existence before creating a new one. ie:

if let existingMapView = LocationSingleton.sharedInstance.singletonMapView { //Display map }else{ let newMapView = //Instantiate new map view controller LocationSingleton.sharedInstance.singletonMapView = newMapView //Display map } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.