views:

1229

answers:

2

I'm trying to kill all memory leaks in my iPhone 3.0 application. CLANG builds with all lights green so now I'm analyzing with Instruments.

This is easier said then done, since it is indicating hundreds of 16 byte leaks after just a few minutes of using the app. It seams to be mainly in UIKit, and the common part is that the end of the stack trace always calls [NSObject respondsToSelector]

Is this something I can ignore or what can be the reason for all these leaks? I I can ignore them, is there a way to filter them out in Instruments, so I can detect the real leaks?

*EDIT I managed to find the part of my code that caused the problem, but I still don't understand why. I have a custom UIView with some text and a spinner that is visible during an async http request. When the request is done I call this method on the view:

- (void)fadeOut{
    spinner.hidden = YES;
    loadingLabel.hidden = YES;
    messageLabel.hidden = YES;
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(fadeComplete)];
        [UIView setAnimationDuration:0.40];
    self.alpha = 0.0;
        [UIView commitAnimations];
}

- (void)fadeComplete{
    [self removeFromSuperview];
}

If I instead simply do

[self removeFromSuperView] without the alpha animation, there is no leaks reported.

See the screenshot below for Instruments details.

Instruments Screenshot

A sample stack trace:

   0 libobjc.A.dylib _malloc_internal
   1 libobjc.A.dylib _cache_addForwardEntry
   2 libobjc.A.dylib lookUpMethod
   3 libobjc.A.dylib class_respondsToSelector
   4 CoreFoundation -[NSObject respondsToSelector:]
   5 UIKit -[UINavigationTransitionView transition:fromView:toView:]
   6 UIKit -[UINavigationTransitionView transition:toView:]
   7 UIKit -[UINavigationController _startTransition:fromViewController:toViewController:]
   8 UIKit -[UINavigationController _startDeferredTransitionIfNeeded]
   9 UIKit -[UINavigationController viewWillLayoutSubviews]
  10 UIKit -[UILayoutContainerView layoutSubviews]
  11 UIKit -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
  12 QuartzCore -[CALayer layoutSublayers]
  13 QuartzCore CALayerLayoutIfNeeded
  14 QuartzCore CA::Context::commit_transaction(CA::Transaction*)
  15 QuartzCore CA::Transaction::commit()
  16 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
  17 CoreFoundation __CFRunLoopDoObservers
  18 CoreFoundation CFRunLoopRunSpecific
  19 CoreFoundation CFRunLoopRunInMode
  20 GraphicsServices GSEventRunModal
  21 GraphicsServices GSEventRun
  22 UIKit -[UIApplication _run]
  23 UIKit UIApplicationMain
  24 Client main **/main.m:14
  25 Client start

And another one:

   0 libobjc.A.dylib _malloc_internal
   1 libobjc.A.dylib _cache_addForwardEntry
   2 libobjc.A.dylib lookUpMethod
   3 libobjc.A.dylib class_respondsToSelector
   4 CoreFoundation -[NSObject respondsToSelector:]
   5 UIKit -[UIViewAnimationState animationDidStart:]
   6 QuartzCore run_animation_callbacks(double, void*)
   7 QuartzCore CA::timer_callback(__CFRunLoopTimer*, void*)
   8 CoreFoundation CFRunLoopRunSpecific
   9 CoreFoundation CFRunLoopRunInMode
  10 GraphicsServices GSEventRunModal
  11 GraphicsServices GSEventRun
  12 UIKit -[UIApplication _run]
  13 UIKit UIApplicationMain
  14 Client main ***/main.m:14
  15 Client start
+1  A: 

Are you sure your delegate method is being called? I think the problem is the animation delegate method, which, according to Apple's documentation, must have this signature:

[UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];

And then you have a method like this in your class:

#pragma mark -
#pragma mark UIView animation delegate method

- (void)animationFinished:(NSString *)animationID 
                 finished:(BOOL)finished 
                  context:(void *)context
{
    [self removeFromSuperview];
}

Probably your animation delegate is not being called, thus, the object is not released.

From the documentation:

setAnimationDidStopSelector:

Sets the message to send to the animation delegate when animation stops.

  • (void)setAnimationDidStopSelector:(SEL)selector

Parameters

selector

The message sent to the animation delegate after animations end. The default value is NULL. The selector should be of the form: - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context. Your method must take the following arguments:

animationID

An NSString containing an optional application-supplied identifier. This is the identifier that is passed to the beginAnimations:context: method. This argument can be nil.

finished An NSNumber object containing a Boolean value. The value is YES if the animation ran to completion before it stopped or NO if it did not.

context

An optional application-supplied context. This is the context data passed to the beginAnimations:context: method. This argument can be nil.

Hope this helps!

Adrian Kosmaczewski
+1  A: 

You didn't specify if you did your checks on the simulator on an actual device, but in my experience running Leaks in the simulator is not very reliable and will report many tiny leaks in the the SDK, while running it on the device will not report any leaks.

Ron Srebro