0

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?

Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • I'm going to guess that layerFindIndicator` has been `dealloc`'ed already. That if statement will not guard against a deallocated object that has not been set to nil. e.g. look for where you are releasing it... – Paul.s Apr 22 '12 at 15:22
  • @Paul.s You've got quite a point here, but I definitely cannot spot where the object mighty have been dealloced... (this is NOT my code, but a fragment of some new additions that made it into the latest Scintilla release, so I'm quite lost). I'm now trying creating the object before that (since it should be created anyway), and it seems to be working (so far, that is...) – Dr.Kameleon Apr 22 '12 at 15:45

2 Answers2

5

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.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
-1

Try this:

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

Also check to see if it is released else were.

EDIT:

Another thing I found was you didn't have an white space in the if. Your code should now look like this:

if (layerFindIndicator != nil){
    if ([layerFindIndicator animationForKey:@"animateFound"]){
        [layerFindIndicator removeAnimationForKey:@"animateFound"];
    }  
}
Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
Allison
  • 2,213
  • 4
  • 32
  • 56
  • 1
    Although personally I would rewrite the OP's original code with the brackets as you have - this makes no difference to the functionality... – Paul.s Apr 22 '12 at 15:38
  • Oh, fail on my part. I though it was a **must**... I think I should re-read my Objective C book. – Allison Apr 22 '12 at 15:40
  • I myself wouldn't normally write it this way (without brackets); I just typed in just for the sake of debugging (and when I'm debugging I personally don't care about styling...) :-) – Dr.Kameleon Apr 22 '12 at 15:42
  • TBH it was the first thing I checked in case there was an error - always handy to have a quick test project or CodeRunner to hand. @Dr.Kameleon I always try to write solid code as you never know when "prototype" code will make it into production for lack of remembering or time constraints. – Paul.s Apr 22 '12 at 15:43
  • @Paul.s Quite true,too... though in my (quite awkward admittedly) coding fashion there are 2 stages : 1) writing, 2) cleaning up (doesn't really make sense, I know; but it's almost I cannot help it.. lol) ;-) – Dr.Kameleon Apr 22 '12 at 15:47
  • I agree most of my mini projects hit the app store one day or another, so I always code for production. – Allison Apr 22 '12 at 15:47
  • @Paul.s Sidenote : after ironing out some weird issues like the one posted in this question, I hope you won't need CodeRunner again... :-) (lol) – Dr.Kameleon Apr 22 '12 at 15:49
  • It seems that most of the coding population uses Code Runner :D – Allison Apr 22 '12 at 15:59