Nicholas Riley
Nicholas Riley

Reputation: 44331

-[NSWindowController window] retaining window when NSWindowController initialized with window?

In an application (OS X 10.6.7) I have a NSWindowController subclass which is initialized with -[NSWindowController initWithWindow:]—i.e., I have already created the window in code; I'm not loading it from a nib.

Normally, I refer to the window in my NSWindowController subclasses with [self window]. But in this case, every time I send [self window], the window gets retained, so I end up leaking quite a lot.

Is this intended behavior? For the moment I've worked around it by just storing the window in an instance variable in the init method and never sending [self window].

I am pretty sure this is not happening because NSWindowController is trying to load the window: -loadWindow does not retain the window and -isWindowLoaded returns YES:

(gdb) set $window = (id)[self window]
Current language:  auto; currently objective-c
(gdb) p (int)[$window retainCount]
$1 = 3
(gdb) p (BOOL)[self isWindowLoaded]
$2 = 1 '\001'
(gdb) call (void)[self loadWindow]
(gdb) p (int)[$window retainCount]
$3 = 3
(gdb) p (int)[[self window] retainCount]
$4 = 4
(gdb) p (int)[[self window] retainCount]
$5 = 5

Upvotes: 2

Views: 1430

Answers (1)

Nicholas Riley
Nicholas Riley

Reputation: 44331

-[NSWindowController window] retaining the window is fine; the issue seems to be related to autorelease pools.

window = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 200, 200)
                                               styleMask:NSTitledWindowMask
                                                 backing:NSBackingStoreBuffered
                                                   defer:NO];
NSWindowController *controller = [[NSWindowController alloc] initWithWindow:window];
[window setTitle:@"testing"];
[window makeKeyAndOrderFront:nil];
[window release];
NSLog(@"[window retainCount]: %d", [window retainCount]);
[controller window];
[controller window];
[controller window];
NSLog(@"[window retainCount]: %d", [window retainCount]);

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[controller window];
[controller window];
[controller window];
NSLog(@"[window retainCount]: %d", [window retainCount]);
[pool drain];
NSLog(@"[window retainCount]: %d", [window retainCount]);

The output is:

2011-06-12 19:26:52.337 window[5517:a0b] [window retainCount]: 1
2011-06-12 19:26:52.339 window[5517:a0b] [window retainCount]: 4
2011-06-12 19:26:52.340 window[5517:a0b] [window retainCount]: 7
2011-06-12 19:26:52.340 window[5517:a0b] [window retainCount]: 4

The problem was that I forgot to create a pool when doing Cocoa stuff in a Carbon event handler (InstallApplicationEventHandler). This matches the context of the thread I linked to.

Ordinarily I see an exception when there's no autorelease pool present, so I'm guessing there is simply a pool in place that never gets drained.

Upvotes: 2

Related Questions