views:

752

answers:

3

I've got a retain/release problem. My View is pretty complicated so I've set NSZombieEnabled to YES and am trying to locate which, exactly, object is causing me grief. To speed this process along I'm wondering if there hints or tricks to tracking the Zombies back to the grave they dug their way out of (sorry, had to) or, back to the object they're associated with? The cryptic console message doesn't appear to offer much insight:

NSInvocation: warning: object 0x1076850 of class '_NSZombie_CALayer' does not implement methodSignatureForSelector: -- trouble ahead

I have no selectors called "trouble ahead".

Edit - Including Stack Trace:

#0  0x3026e017 in ___forwarding___
#1  0x3024a0a2 in __forwarding_prep_0___
#2  0x302042e8 in CFRelease
#3  0x00c4fc31 in CALayerUpdateSublayers
#4  0x00c4e173 in -[CALayer dealloc]
#5  0x00c4000e in CALayerRelease
#6  0x00c48dad in CALayerFreeTransaction
#7  0x00c410b8 in CA::Transaction::commit
#8  0x00c492e0 in CA::Transaction::observer_callback
#9  0x30245c32 in __CFRunLoopDoObservers
#10 0x3024503f in CFRunLoopRunSpecific
#11 0x30244628 in CFRunLoopRunInMode
#12 0x32044c31 in GSEventRunModal
#13 0x32044cf6 in GSEventRun
#14 0x309021ee in UIApplicationMain
#15 0x00001eb4 in main at main.m:14

Edit 2: ObjectAlloc

Looking up the memory address in question in ObjectAlloc I find two matches:

#    Address     Category         Creation Time    Size Responsible Library Responsible Caller
0   0x1076980 GeneralBlock-48    00:11.470    48    QuartzCore  -[CALayer setDelegate:]
1   0x1076980 CALayer            00:11.552    48    UIKit    -[UIView _createLayerWithFrame:]

Digging into #0 GeneralBlock-48:

#   Category     Event Type Timestamp Address Size Responsible Library Responsible Caller
0   GeneralBlock-48 Malloc     00:11.470 0x1076980 48 QuartzCore -[CALayer setDelegate:]
1   GeneralBlock-48 Free     00:11.551 0x1076980 -48 QuartzCore -[CALayer addAnimation:forKey:]
2   CALayer         Malloc     00:11.552 0x1076980 48 UIKit -[UIView _createLayerWithFrame:]

Digging into #1 CALayer:

#   Category     Event Type Timestamp Address    Size Responsible Library Responsible Caller
0   GeneralBlock-48 Malloc     00:11.470 0x1076980 48 QuartzCore -[CALayer setDelegate:]
1   GeneralBlock-48 Free     00:11.551 0x1076980 -48 QuartzCore -[CALayer addAnimation:forKey:]
2   CALayer         Malloc     00:11.552 0x1076980 48 UIKit -[UIView _createLayerWithFrame:]

Well, I see now that drilling deeper in either #0 or #1 reveals the exact same information. I suppose that should cut troubleshooting this in half...but I'm still at a loss...

+2  A: 

One quick thing you can do is set a symbolic breakpoint on objc_exception_throw. This will cause your program to pause whenever an exception is thrown. This may not help you track down exactly which CALayer is giving you grief, but it should help you find the general vicinity where it's being called.

Alex
agreed, you need to know exactly when this is happening.
Corey Floyd
I had the objc_exception_throw breakpoint enabled but it's just as cryptic, to me. I've posted it above.
Meltemi
What's the context for this error? What do you do with your program to make it fire? From the stack trace, it looks like it's happening at the end of a CA transaction, which means it's a safe bet that this is coming at the end of an animation. Is there an animation firing? If so, which layers are involved? Are you making sure to `retain` ones you intend to use again?
Alex
this error happens when returning to a table view from a detail view by using the standard backBarButtonItem. The detail view in question is somewhat complicated in that its VC has a view which has 3 subviews. two of which are of the same class...the 3rd is different. each of these subviews has their own subviews. Anyway, I'm trying to follow the retain/release rules where a child/subview doesn't retain its parent. All works fine except for those two subview siblings of same class. If I ASSIGN their connection to the parent we get this crash. if I RETAIN it things work but We're leaking..ARGH!
Meltemi
Can you explain that a little bit more? I understand you have a view controller whose view has three subviews, two of which are of the same class. You also said these views also have a parent -- is this your detail view controller? Does the detail view controller retain a reference to the two subviews?
Alex
Turns out, of those two sibling subviews that were the same class, one wasn't being set properly with the accessor methods. This was a stupid lingering mistake on my part from a month or so ago...but, man, was it difficult (for me) to troubleshoot. I learned something about Instruments though. Very handy little app that Instruments! Thanks for all the help, and humorous anecdotes, everyone!
Meltemi
+3  A: 

I believe the backtrace is just the point where the zombie is being messaged. This backtrace usually gives you zero information about what is causing the crash. It pretty much only tells you the type and the address of the object that is being over-released.

A technique I often use to track down over-releases like this is to use Instruments' ObjectAlloc to track all retains and releases. Find the address for the over-released object in ObjectAlloc, then list all the retain/release calls, and then try to balance each retain with a release. Once you find a release without a retain to match, You've found the problem.

kperryua
Sorry but how do you "list all the retain/release calls" in Instruments?
Meltemi
In the tableview showing all the allocations, click the arrow next to "* All Allocations *". Search for the address of the zombie CALayer (you can paste it in the search field below). Click on the arrow next to that address. You'll see a listing of all malloc/free/retain/release calls on that address. Open the sidebar to see the stack trace for each call.
kperryua
Thanks! Helpful! But when I run with ObjectAlloc the NSZombies don't show up. So I can't compare that address to what's in the list. I believe Instruments circumvents the Debugger as well as XCode's console. Ah, I think I just answered that part of the question: Look in Console.app and not XCode's console...
Meltemi
OK, I have two hits for that memory address. I'll put them above as I'm not figuring this out...
Meltemi
Meltemi
+2  A: 

“trouble ahead” is part of the warning, not the selector. The warning itself comes from NSInvocation, but the fact that it mentions “class _NSZombie_CALayer” means that something’s trying to work with a CALayer that’s been dealloced.

The stack trace indicates that this is happening when a layer is trying to release its sublayers.

Altogether, this means that the layer being released has a sublayer that has been over-released somewhere in your code. Check your memory management of CALayers, or try the Clang Static Analyzer.

Ahruman