views:

540

answers:

2

I'm developing a Cocoa user interface for a Photoshop CS3 plugin using Bindings. (Carbon in Cocoa, since PS is a Carbon app) I'm getting a EXC_BAD_ACCESS error when I close my modal NSWindow and the NSAutoreleasePool releases.

I believe it has something to do with bindings and the control views I have in my nib file, because when I remove the bindings from the check boxes and radio buttons from the nib, the window can close an unlimited number of times and not crash.

I've spent hours now with Instruments trying to figure out which object might be getting released early (or double released) and cannot find it.

Now my thoughts are that maybe there is something I'm missing about running a modal window within an NSAutoreleasePool while using Cocoa Bindings. Like maybe there is something I'm supposed to do before closing the window to "finalize" all the bindings to prevent them from sending messages to released objects.

Here is a basic code example of what I'm doing:

NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];    
NSApplicationLoad();
ExportWindowController *controller = [[ExportWindowController alloc] initWithWindowNibName:EXPORT_CONTROLLER_NIB_NAME];

[controller showWindow:nil];
[NSApp runModalForWindow:[controller window]];
[controller close];

[controller release];
[localPool release];

The modal window is closed by a call to:

[NSApp stopModal];

Here is a stack trace:

#0  0x97793869 in _cache_getMethod
#1  0x9779c6da in lookUpMethod
#2  0x97793da7 in _class_lookupMethodAndLoadCache
#3  0x97793953 in objc_msgSend
#4  0x96501151 in -[NSBinder releaseConnectionWithSynchronizePeerBinders:]
#5  0x96a10390 in -[NSValueBinder releaseConnectionWithSynchronizePeerBinders:]
#6  0x963ac895 in -[NSObject(_NSBindingAdaptorAccess) _releaseBindingAdaptor]
#7  0x964062f5 in -[NSView _releaseBindingAdaptor]
#8  0x96405784 in -[NSView _finalizeWithReferenceCounting]
#9  0x96404e2f in -[NSView dealloc]
#10 0x964ef163 in -[NSControl dealloc]
#11 0x9099a9d8 in CFRelease
#12 0x909c75bd in _CFAutoreleasePoolPop
.... more

Turning on NSZombieEnabled did not turn up any double-released objects (although there was 1 from Photoshop itself)

Turning off all bindings gets rid of any crash.

Any ideas?

+2  A: 

You are correct that the bindings seem to be causing the problem as the stack crawl indicates. However, I think that is just the symptom, not the problem.

As you are aware, Cocoa in a Carbon application can be tricky.

When you write, "the ExportWindowController runModalWindowForExport is this:" am I to understand these points:

  1. ExportWindowController is a class based off of NSWindowController?
  2. If so, when do you dismiss the window? I see [self close] but, I don't see any "close" selector associated with NSWindowController. Should you be calling:

    [[controller window] performClose:[NSApplication sharedApplication]];
    

? 3. Also, is NSApp instantiated? Do you see your window? I've had to use [NSApplication sharedApplication] to get it working right sometimes....

Let me know if any of this helps.

EDIT: Nov 6, 2009: 16:15 EST: What happens if you have only one Cocoa binding? Are you releasing the data that the binding is bound to first? Perhaps you shouldn't be if so...

EDIT: Nov 9, 2009: 16:27 EST:I was recently working in a plug-in that works with a Carbon application. This plug-in is using Cocoa as its basis. Everything was going splendidly until I added NSTrackingAreas to my NSControls. Then I started seeing all sorts of crashes when the plug-in's NSAutorelease pool was being drained. I solved this problem by calling each NSControl's removeTrackingArea function.

Perhaps you need to do something similar for your NSWindowController based object? In the dealloc selector, try calling code to removeObserver:forKeyPath on each object that you have a binding to?

Lyndsey Ferguson
The window does open and a previous incarnation of this UI (simpler, and w/out bindings) did work just fine.ExportWindowController is a subclass of NSWindowController, which does have a close method. I've also tried it the way you describe above, however it doesn't seem to help w/ the crash. The NSApp convention is something I believe I got from Apple examples a while back. Changing that to [NSApplication sharedApplication] doesn't seem to change the crash.Thanks for your help! Keep it coming, especially if anything i just said jogs anything for you!
Jess Bowers
As I understand it, [NSApplication sharedApplication] should be returning NSApp anyway -> I've had to use the class selector in a plug-in as NSApp wasn't working for me at the time.
Lyndsey Ferguson
If I reduce the interface in the nib file down to a single binding, it still crashes. I am currently searching for a solution to the problem of "finalizing" the bindings. no luck yet! :(
Jess Bowers
What is being bound? What is it being bound to?Is it possible to add a NSLog statement to the dealloc selector of the bound object, the binding object, and the NSWindow controller's close to see the order in which the objects are being deleted?
Lyndsey Ferguson
+1  A: 

If it is crashing when the NSAutoreleasePool is being drained, it is because something is being over-released. You should be able to turn on Zombie detection to figure out what; to find the type of the object being over-released.

At a complete guess, do you implement a -dealloc method in ExportWindowController? If so, are you -releaseing an object that was created by the NIB load for which a -retain did not occur upon load?

bbum
No dealloc on the ExportWindowController or double-releasing of nib-based objects here, but I will go back and re-do the Zombie detection tests in Instruments. I've found that useful in the past, but this time it doesn't seem to be showing me useful info. Or rather overwhelming amount of data. (I probably need to re-read the docs on hunting zombies). Thanks for the help, Bill!
Jess Bowers
No luck looking at the zombies. I've updated the question to also add that this is a Photoshop CS3 plugin. Not sure if that was relevant initially, but now I'm thinking omitting that info was a mistake :)
Jess Bowers