Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MKMapView autorelease not calling dealloc after UIViewController is popped

I have the following code in class A:

UIViewController *vc = [self viewControllerForItem:item];

where the viewControllerForItem method in my app delegate returns a UIViewController based on my item i.e.

vc = [[[MyCustomViewController alloc] init] autorelease];

return vc;

I then push the view controller:

[self.navigationController pushViewController:vc animated:YES];

This VC i'm trying to push is a MKMapView and I inserted a log statement in the dealloc method to see if it's being called. In my memory usage, the growth is increasing pretty rapidly.

However, when I add the following code after pushing the VC:

[vc release];

my MKMapView class calls the dealloc method.

Of course this would be a simple solution if the MKMapView class was the only class returned by my app delegate (or I could just check if the VC's class is my MKMapView class). However, I would like to solve the root problem of this.

  1. Why is the dealloc not being called if I set autorelease on my view controller?

  2. How is it possible that I can add [vc release] to the view controller even though autorelease is used on that vc?

Thanks

Edit:

Here's some additional info. I have the viewControllerForItem class in my app delegate. I'm returning the auto released object into my other manager class where I then push the view controller. Is the retain count being messed up when I return an autoreleased object, and then push it in some other class?

This is the backtrace / callstack right when I push the VC and when the mkmapview's didDissappear is called:

pushVC: (
0   NewHampshire                        0x00254cdf -[CustomViewController navigateToRowId:withLinkBehavior:animated:] + 2111
1   NewHampshire                        0x002534c9 -[CustomViewController webView:shouldStartLoadWithRequest:navigationType:] + 841
2   UIKit                               0x02caf288 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 318
3   UIKit                               0x02cb1854 -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 77
4   CoreFoundation                      0x05d0bd1d __invoking___ + 29
5   CoreFoundation                      0x05d0bc2a -[NSInvocation invoke] + 362
6   CoreFoundation                      0x05d0bdaa -[NSInvocation invokeWithTarget:] +     74
7   WebKit                              0x0a4d811d -[_WebSafeForwarder forwardInvocation:] + 157
8   CoreFoundation                      0x05d076da ___forwarding___ + 458
9   CoreFoundation                      0x05d074ee _CF_forwarding_prep_0 + 14
10  CoreFoundation                      0x05d0bd1d __invoking___ + 29
11  CoreFoundation                      0x05d0bc2a -[NSInvocation invoke] + 362
12  WebCore                             0x09533b29 _ZL20HandleDelegateSourcePv + 121
13  CoreFoundation                      0x05ca083f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
14  CoreFoundation                      0x05ca01cb __CFRunLoopDoSources0 + 235
15  CoreFoundation                      0x05cbd29e __CFRunLoopRun + 910
16  CoreFoundation                      0x05cbcac3 CFRunLoopRunSpecific + 467
17  CoreFoundation                      0x05cbc8db CFRunLoopRunInMode + 123
18  GraphicsServices                    0x059749e2 GSEventRunModal + 192
19  GraphicsServices                    0x05974809 GSEventRun + 104
20  UIKit                               0x02a6ed3b UIApplicationMain + 1225
21  NewHampshire                        0x000150dd main + 125
22  libdyld.dylib                       0x04fab70d start + 1
)

disappear: (
0   NewHampshire                        0x0014631d -[CustomAdvancedGPSMapViewController viewDidDisappear:] + 173
1   UIKit                               0x02b85bac -[UIViewController _setViewAppearState:isAnimating:] + 341
2   UIKit                               0x02b86328 -[UIViewController __viewDidDisappear:] + 150
3   UIKit                               0x02b86461 -[UIViewController _endAppearanceTransition:] + 306
4   UIKit                               0x02ba549a -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 738
5   UIKit                               0x02b9d403 __49-[UINavigationController _startCustomTransition:]_block_invoke + 206
6   UIKit                               0x03176740 -[_UIViewControllerTransitionContext completeTransition:] + 99
7   UIKit                               0x02a63454 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke105 + 680
8   UIKit                               0x02ad1005 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 306
9   UIKit                               0x02abac6c -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 267
10  UIKit                               0x02abaf58 -[UIViewAnimationState animationDidStop:finished:] + 80
11  QuartzCore                          0x028b2a44 _ZN2CA5Layer23run_animation_callbacksEPv + 304
12  libdispatch.dylib                   0x04d194b0 _dispatch_client_callout + 14
13  libdispatch.dylib                   0x04d0775e _dispatch_main_queue_callback_4CF + 340
14  CoreFoundation                      0x05d7ca5e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
15  CoreFoundation                      0x05cbd6bb __CFRunLoopRun + 1963
16  CoreFoundation                      0x05cbcac3 CFRunLoopRunSpecific + 467
17  CoreFoundation                      0x05cbc8db CFRunLoopRunInMode + 123
18  GraphicsServices                    0x059749e2 GSEventRunModal + 192
19  GraphicsServices                    0x05974809 GSEventRun + 104
20  UIKit                               0x02a6ed3b UIApplicationMain + 1225
21  NewHampshire                        0x0001507d main + 125
22  libdyld.dylib                       0x04fab70d start + 1
)

Solution: Although the responses in this post didn't provide the exact solution to my problem, Darren definitely steered me into the correct direction using the instruments tool. I found the culprit to be a CABasicAnimation object that was not being properly released.

in the viewWillDisappear method, I added the following for the CABasicAnimation object:

self.rotationAnimation.delegate = nil;
self.rotationAnimation = nil; 
like image 940
kevinl Avatar asked Jan 14 '14 21:01

kevinl


2 Answers

Use Instruments to track the retain/release history of CustomAdvancedGPSMapViewController and/or MKMapView :

  • In Xcode, select "Product > Profile" from the menu.

  • When Instruments starts, select the "Allocations" template.

  • If your app starts automatically, click the "Stop" button to stop it.

  • Click the "i" button on the Allocations instrument, and check "Record reference counts".

  • Select "View > Extended Detail" from the menu.

  • Click the "Record" button to start your app, and wait for your app to start in the simulator.

  • In the simulator, use your app to navigate to the CustomAdvancedGPSMapViewController.

  • In Instruments, click the "Pause" button

  • Use the search field in the top-right of the window and search for CustomAdvancedGPSMapViewController. CustomAdvancedGPSMapViewController should appear in the Allocation Summary list.

  • In the Allocation Summary list, Click the -> arrow next to the CustomAdvancedGPSMapViewController name. This should show that you have one instance of CustomAdvancedGPSMapViewController active in your app.

  • Click the -> arrow next to address. This will display the retain/release history for this CustomAdvancedGPSMapViewController instance.

  • Un-pause Instruments, return to the simulator, and dismiss your CustomAdvancedGPSMapViewController and return to the point where you believe the controller should be deallocated.

  • Return to Instruments, click "Pause" again, and look at the updated retain/release history.

The first event in the retain/release history should be "malloc". Select this row and the Extended Detail view in the right side of the window will display the stack trace for this allocation. You should see your own code in the stack trace. Double-click your code in the stack trace and you should see your line of code that allocated the the CustomAdvancedGPSMapViewController instance.

Above the code view, click the "History" tab to return to the history list.

The last event in the retain/release history should be "free". If that's not the case there may be a leak. Inspect the retain/release history and look for an unmatched retain. There may be a lot of noise, related to CoreAnimation, etc. Look for events in which your code appears in the stack trace.

Compare the retain/release history with a different view controller that is not leaking.

If CustomAdvancedGPSMapViewController isn't leaking, try inspecting the history of MKMapView.

like image 88
Darren Avatar answered Nov 04 '22 06:11

Darren


The code which you have written is correct and you should not be releasing vc since it is been autoreleased already.

-(UIViewController *) viewControllerForItem: (Item*)item
{
   /* create controller for the item --
    * alloc init with increase the retain count of your object by 1
    * autorelease will reduce the retain count of the object by 1 
    */
    return  [[[MyCustomViewController alloc] init] autorelease]; 
}


UIViewController *vc = [self viewControllerForItem:item];
[self.NavigationController pushViewController:vc];

You cannot release 'vc' since you dont own it, in the sense you have not done 'alloc init' or 'retain' for it.

I have faced issues with Mapview's not releasing the memory even after getting released. It seems to be an apple bug and this memory will be destroyed only when you get a memory warning for mapview. But you can force the release by doing a hack.

Changing the mapType appears to release the memory the mapview is holding. So try resetting the mapType just before the release of the mapview object in mapviewcontroller. You can see the memory going down just after that statement is executed.

- (void)dealloc
{
  // this is a trick for releasing memory
  __mapView.mapType = MKMapTypeStandard;
 [__mapView removeFromSuperview];
  __mapView.delegate = nil;
 [__mapview release];
 [super dealloc];
}

Hope it helps.

like image 2
Anki Avatar answered Nov 04 '22 05:11

Anki