Search code examples
objective-ccocoaexc-bad-accessquartz-graphicscagradientlayer

EXC_BAD_ACCESS on animationForKey:


I'm trying to use a recent feature of the Scintilla component, which provides OSX-like text-highlighting effect (the yellow animated bouncing box), and I'm stuck with an error that pops up intermittently :

EXC_BAD_ACCESS

pointing to this particular line :

if (layerFindIndicator!=nil)
        if ([layerFindIndicator animationForKey:@"animateFound"])
            [layerFindIndicator removeAnimationForKey:@"animateFound"];

(the ifs are mine; just in case I caught the object layerFindIndicator being nil, or deallocated or whatever... Unfortunately, it doesn't help...)

layerFindIndicator is seemingly a subclass of CAGradientLayer. (You may see the full code for layerFindIndicator, here).

Since, I'm an absolute newbie to Quartz Core, could please give me any hint as to HOW this could be debugged?


Solution

  • Since, I'm an absolute newbie to Quartz Core, could please give me any hint as to HOW this could be debugged?

    This doesn't have anything to do with QuartzCore specifically (at least, I hope not)—it's general this-object-has-been-killed-before-its-time-how-do-I-find-the-killer stuff.

    In Xcode:

    1. Edit your current scheme.
    2. For the Profile action, set it to use the Debug build configuration.
    3. Dismiss that and then hit the Profile command.

    Xcode will build for that action and then launch Instruments.

    Instruments will prompt you to choose a template; you want the Zombies template. Once you've chosen it, Instruments will create a trace document and run your application. Switch to your application (if it isn't already frontmost), then do whatever causes the crash.

    If the crash really is a dead-object crash, Zombies will reveal it. You'll get a flag in Instruments's timeline saying something like “message sent to zombie object 0xd3c2b1a0”, and your program will probably exit shortly thereafter.

    In that flag is a tiny little button that looks like this: ➲ except it'll be gray. Click on it.

    That takes you to the history of that object (actually of that address, including any previous objects or other allocations that have started at that address). Show your Extended Detail Pane (the one that appears on the right showing a stack trace), then scroll down to the end and then move backward (upward) step by step through time, looking at releases and autoreleases, looking for the one that isn't balancing out the object's allocation or a retain.

    The solution will probably involve one or more of:

    • Changing a property to be strong or weak rather than assign/unsafe_unretained
    • Adding a property where you previously did not strongly own an object
    • Rearchitecting some things, if it's not clear which of the above you need to do or if either one of them seems like a filthy hack
    • Switching to ARC to get weak properties and __weak instance variables (both of which get set to nil automatically when the referenced object dies) and to get local variables being implicitly initialized to nil

    But it'll depend on what you find in Instruments. And, of course, there's the chance that your problem—the bad access—isn't a dead object at all and all of the above will not help you.