35

I've noticed that my app leaks memory, but if I take the MKMapView out the memory problem goes away.

To test the theory, I made a dead simple project that has a view that pushes a view with a MKMapView in it and pops and pushes. Nothing more. No code in the view controllers, everthing done via storyboard.

If I go back and forth to the map view, it starts about 3MB after doing pushing and popping the view with the map in it this about 15 times the memory is around 230MB.

Anyone else seen this? Seems like a pretty big bug. Is there a different way to use MKMapView that will prevent it from leaking so much?

enter image description here

Kevin Chen
  • 994
  • 8
  • 24
codercat
  • 22,873
  • 9
  • 61
  • 85
  • 2
    I see this behavior in my App too and for me the question is clear: What is happening here? Is this a real memory leak (it seems so) and has someone figured out what is going wrong and how to fix. – Frank Hartmann Dec 03 '13 at 10:10
  • Try to remove the MKMapView in viewDidDisappear method, example : [self.outMapView removeFromSuperview]; self.outMapView = nil; – Kuo Ming Lin Jan 04 '14 at 17:13
  • probably should log a radar ticket. – johndpope Jan 28 '14 at 03:25
  • 1
    search and you find dozens of these questions here and on other forums - file a radar. nothing else you can do since the map is broken – Daij-Djan Aug 16 '14 at 14:52
  • Still broken in iOS 9.x. I solved it by storing a reference to MKMapView in a static variabled and reusing the same Map over and over again. – vilmoskörte Feb 24 '16 at 11:22
  • See http://stackoverflow.com/a/35601554/723276 – vilmoskörte Feb 24 '16 at 12:08
  • Possible duplicate of [iOS6 MKMapView using a ton of memory, to the point of crashing the app, anyone else notice this?](https://stackoverflow.com/questions/12641658/ios6-mkmapview-using-a-ton-of-memory-to-the-point-of-crashing-the-app-anyone-e) – Yoh Deadfall Mar 26 '18 at 13:51

3 Answers3

18

I had faced the same issue and (thanks to Stackoverflow) fixed it by changing MKMapType in viewWillDisappear and deallocating/setting its delegate to nil.As it still sends message to delegates. This is documented in MKMapViewDelegate Protocol Reference:

Before releasing an MKMapView object for which you have set a delegate, remember to set that object’s delegate property to nil. One place you can do this is in the dealloc method where you dispose of the map view

.

-(void)viewWillDisappear:(BOOL)animated{
  [super viewWillDisappear:animated];
  [self applyMapViewMemoryFix];

}

- (void)applyMapViewMemoryFix{

switch (self.mkMapView.mapType) {
    case MKMapTypeHybrid:
    {
        self.mkMapView.mapType = MKMapTypeStandard;
    }

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

        break;
    default:
        break;
}
self.mkMapView.showsUserLocation = NO;
self.mkMapView.delegate = nil;
[self.mkMapView removeFromSuperview];
self.mkMapView = nil;
}

hope this helps

iAhmed
  • 6,556
  • 2
  • 25
  • 31
  • 5
    Doesn't help. Still leaking. – durazno Aug 16 '15 at 20:25
  • Yes, it's also still leaking for me. I have the map view in a `UICollcetionViewCell` so I can't call this code from `viewWillDisappear`. Calling it in the cell's `deinit` doesn't work. – fruitcoder Sep 28 '16 at 13:14
5

Swift Version:

override func viewWillDisappear(_ animated:Bool) {
    super.viewWillDisappear(animated)
    self.applyMapViewMemoryFix()
}

func applyMapViewMemoryFix() {
    switch (self.mapView.mapType) {
    case MKMapType.hybrid:
        self.mapView.mapType = MKMapType.standard
    case MKMapType.standard:
        self.mapView.mapType = MKMapType.hybrid
    default:
        break
    }
    self.mapView.showsUserLocation = false
    self.mapView.delegate = nil
    self.mapView.removeFromSuperview()
    self.mapView = nil
}
Nosov Pavel
  • 1,571
  • 1
  • 18
  • 34
fede1608
  • 2,808
  • 1
  • 16
  • 17
4

The best solution I have found is to have an instance of MKMapView in your delegate, you will allocate it only once.

Then anytime you need a MapView, you just use the one from the delegate.

In my case i needed to clean the annotations from it as soon as the view willDisappear ( to not have older annotations on the map ).

  - (void)viewDidLoad {
      AppDelegate *delegate = [UIApplication sharedApplication].delegate;
          if (!delegate.appModel.mapView)
             delegate.appModel.mapView = [[MKMapView alloc] initWithFrame:self.view.frame];
      self.mapView = delegate.appModel.mapView;
      [self.mapView setFrame:self.view.frame];
      [self.mapView setDelegate:self];
      [self.view addSubview:self.mapView];
   }

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.mapView removeAnnotations:self.mapView.annotations];
    for (id<MKOverlay> overlay in self.mapView.overlays) {
        [self.mapView removeOverlay:overlay];
    }
}
xGoPox
  • 674
  • 8
  • 23