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?
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...
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:
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":
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 ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With