MKDotBounceAnimation animationDidStop bug
MKMapViews seem buggy when created problematically.
Some tips:
- set the delegate to nil when the delegate dealloc’s, as per that advice to fix one of the crashbugs
- Either make the instance it static so you never release it, or schedule a delayed ‘release’ command to avoid theanimationDidStop crashbug.
What I do to avoid theanimationDidStop crash is instead of calling release directly, I call it after a delay of 4 seconds. This is easy with this statement:
[mapView performSelector:@selector(release) withObject:nil afterDelay:4.0f];
Just gives the internal stuff a chance to clean itself up before the release is sent.
EDIT: if you read the comments below, there are some even better workarounds. Jayant offers this approach which is much cleaner:
[mapView.layer removeAllAnimations];
It seems this MKDotBounceAnimation problem only occurs with problematically created MKMapViews (not XIB ones), as my XIB one never seems to crash with that error.
PS. I’m the author of the app GPS Log, please check it out :)


January 8th, 2010 at 14:05
Even though I am using a nib file to create a MKMapView object, I meet a bug above sometimes. The bug is usually show up to me when I try to pop a top controller (which has a MKMapView object) on the navigation controller. IPhone SDK always call [MKDotBounceAnimation animationDidStop:finished:] and seems to free a object that is already freed.
February 4th, 2010 at 13:23
I’ve hit this bug mainly when I am testing (popping a view on, then quickly off before the current location has settled down from it’s bounce.) I’ve had some success setting show user location to NO, removing all annotations, unsetting the delegate inside “viewWillDisappear” … but when I tried that today (on a map view inside a cell) I didn’t have access to that event, and doing these ‘tricks’ in the cell dealloc failed for me.
You fix is somewhat distateful but totally working (given current testing), so BIG thank you!
BTW: My assumption is that your delay allows the bounce animation end event to occur, and notify (access) a not-yet-released object, so the crash doesn’t occur. Hopefully Apple will fix this soon.
February 5th, 2010 at 22:36
It’s a nasty bug.
My latest workaround is just to never release it. I create it as a singleton so it doesn’t leak like crazy and just keep reusing the one instance.
Never release = never get the bug! :) and maybe less distasteful than a delayed release.
February 9th, 2010 at 01:39
The following code will fix the bug by preventing the call of animationDidStop if the animation did not complete …
@protocol FixedAnimationDelegate
- (void)fixedAnimationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag;
@end
void fixedAnimationDidStop(id self, SEL cmd, CAAnimation *theAnimation, BOOL finished)
{
@try
{
if (cmd != NULL && finished)
[self fixedAnimationDidStop:theAnimation finished:finished];
else
NSLog(@”prevented map annotation view animation from causing a crash”);
}
@catch (NSException *e)
{
NSLog(@”prevented map annotation view animation from causing a crash”);
}
}
+ (void)initWorkarounds
{
Class MKDotBounceAnimationClass = NSClassFromString(@”MKDotBounceAnimation”);
if (MKDotBounceAnimationClass != nil)
{
class_addMethod(MKDotBounceAnimationClass, @selector(fixedAnimationDidStop:finished:), (IMP)fixedAnimationDidStop, “v@:@c”);
Method orgMethod = class_getInstanceMethod(MKDotBounceAnimationClass, @selector(animationDidStop:finished:));
Method fixedMethod = class_getInstanceMethod(MKDotBounceAnimationClass, @selector(fixedAnimationDidStop:finished:));
method_exchangeImplementations(orgMethod, fixedMethod);
}
}
February 17th, 2010 at 04:50
Perfect article, allowed me to save same problem but a bit different way
My case was following: I leave screen with mapView, screen deallocs and in short after this (screen already destroyed) timer routine attempts to do this animation on deleted screen
setting mapview delegate to nil sure doesn’t help: timer routine is already scheduled
Solution: delay destruction of screen object exact the way you suggested
- (void)dealloc {
if(false) [super dealloc];
[super performSelector:@selector(dealloc) withObject:nil afterDelay:4.0f];
}
March 23rd, 2010 at 03:34
Has anyone tried?
- (void)viewWillDisappear:(BOOL)animated {
[mapView.layer removeAllAnimations];
}
April 29th, 2010 at 16:56
@jayant: your code works great!
April 30th, 2010 at 15:40
great idea Jayant! Not nearly as hacky as my workaround.
May 4th, 2010 at 01:34
Rather than a specific layer this should just pull all you annotations. Turning of showsUserLocation afterward might border on superstition but I do it anyway.
[self.mapView removeAnnotations:self.mapView.annotations];
self.mapView.showsUserLocation = NO;
May 25th, 2010 at 14:09
Nick actually disabling user location allows the user location annotation to be added when you repopulate the annotations. Thats good stuff!