Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory Leak in MapKit iOS8

I've read the other StackOverflow Questions and Answers, and understand this is a bug since iOS6 (or by design, having to deallocate the delegate, then view, who knows). I don't know why or how it hasn't been fixed.

Anywho, I've added the hot fixes from the other answers (below, for future readers):

- (void) viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [self applyMapViewMemoryHotFixOnDisappear];
}

- (void)applyMapViewMemoryHotFixOnDisappear{
    [self applyMapViewMemoryHotFix];
    self.mapView.showsUserLocation = NO;
    self.mapView.delegate = nil;
    self.locationManager.delegate = nil;
    [self.mapView removeFromSuperview];
    self.mapView = nil;
}

- (void)applyMapViewMemoryHotFix{
    switch (self.mapView.mapType) {
        case MKMapTypeHybrid:
        {
            self.mapView.mapType = MKMapTypeStandard;
        }

            break;
        case MKMapTypeStandard:
        {
            self.mapView.mapType = MKMapTypeHybrid;
        }

            break;
        default:
            break;
    }
    self.mapView.mapType = MKMapTypeStandard;
}

-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    [self applyMapViewMemoryHotFix];
}

However, the question I have is, why does the memory not drop to before MapKit levels?

Memory Usage Before / After MapKit

Is there something else I'm missing? Is this expected behaviour? There are no memory leaks judging by the profiler but obviously something isn't right...

like image 636
SparkyRobinson Avatar asked Nov 11 '22 00:11

SparkyRobinson


1 Answers

Despite the use of the so beloved MemoryHotFix by the SO community regarding this problem, you should be sure that you're not holding any strong reference. As others have told, if you're using (read instantiating) views that hold a reference to the view controller they're in and that same view controller as a reference to that view you might get into a Strong Reference Cycle.

Such situation might block your deinit/dealloc methods rendering your cleanups unnecessary and useless.

As stated in the documentation:

You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references.

So be sure to:

  1. Check if your deinit(swift)/dealloc is actually being called (if not, it may indicate a Strong Reference Cycle).
  2. Actually nil the delegates of the MKMapView and LocalitionManager as well as themselves.

Like this:

self.mapView.delegate = nil
self.mapView = nil
self.locationManager?.delegate = nil
self.locationManager = nil

Proof

Having that in mind, here is an example where there is one VC pushing another VC with a MKMapView, every vertical red line means "pushing new VC" and every green line means "popping it":

enter image description here

There's some initial setup (starting at 50 Mb +/-), but future push's don't cause any memory leak as shown. It is worth mentioning that this was captured using a real device. I've tested it using the simulator too and the results are coerent despite the initial setup being much higher (starting at 100 Mb).

Hope you guys can fix it and you might, as well, check your project for Strong Reference Cycles that might compromise your product in the future ;)

like image 192
couceirof Avatar answered Nov 14 '22 21:11

couceirof