I have a window that won't release

Discussion in 'Mac Programming' started by BadWolf13, Mar 11, 2011.

  1. BadWolf13 macrumors 6502

    Joined:
    Dec 17, 2009
    #1
    One of the windows in my program isn't releasing when I close it. According to the Allocations tool in Instruments, the window controller still exists after the window is closed. The "Release When Closed" option is checked in Interface builder, and garbage collection is "required," so I can't figure out what's going on. Anyone got any ideas?
     
  2. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    A window controller isn't the same as the window itself. They are separate objects.

    How are you creating the window controller and storing its reference?
     
  3. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #3
    I'm aware of that, but given their connection, don't they generally release at the same time?

    Creating it with these lines;

    Code:
    	if (!findContactController) {
    		findContactController = [[FindContactController alloc] initWithPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    	}
    
    Not sure what you mean by "storing its reference." What exactly does that mean?
     
  4. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #4
    What ever class that code's from has a findContactController instance variable, I presume. That is storing a reference to the controller object, preventing it from being garbage collected. The window controller will stick around until findContactController is set to nil or another instance of FindContactController.

    BTW According to the docs for isReleasedWhenClose in NSWindow, release when closed is ignored for windows owned by window controllers.
     
  5. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #5
    Thank you, but I find one flaw in that theory. The windows created and stored with;

    Code:
    	ContactWindowController *newWindowController = [[ContactWindowController alloc] initWithNewContactInManagedObjectContext:managedObjectContext];
    
    	[[self windowControllers] addObject:newWindowController];
    
    Are getting released when they're closed. They both have window controllers, the main difference being that one is stored in an array of window controllers, and one is just one of a kind. Is there something else that I'm missing?
     
  6. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #6
    His "theory" is correct. Since you never clear out the reference, the window controller never gets collected.

    NSDocument most likely is handling the closing of the window and remove its corresponding window controller from the array.

    Since you're managing the controller yourself you need to do the same and set the reference to nil for it to collect.

    With GC off you'd still need to do the same thing, only thing different is you'd be calling release/autorelease in addition.
     
  7. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #7
    I'm glad for the advice, but I think you're misunderstanding a few things. This is not a document based app, so there's no NSDocument to speak of. In addition, the window controller in the array is the one that IS getting released. The one that's solo is the one that's not being released. I'm not sure what other information I can give to help.
     
  8. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #8
    Wait, there is something else to note. There's a second window, an NSPanel in the same NIB file, which gets called as a sheet. Could that mess this up?
     
  9. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #9
    Okay, let's see we can get onto the same page.

    Is the first code snippet you gave in ContactWindowController?

    Where is findContactController declared?

    Is it the find contact controller that's not being released?

    Is findContactController assigned anywhere else is in your code other than in the code snippet given?
     
  10. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #10
    No, it's in the AppDelegate, as is the other snippet.

    In the header for the AppDelegate.

    Yes.

    No.
     
  11. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #11
    Then I don't see how my original response doesn't stand.

    An object cannot be garbage-collected while any other object has a (strong) reference to it.

    Your code will allocated and assign a find contact window controller to the findContactController instance variable in your application delegate. From that point on there is always another object with a reference to the find contact window controller, that being your application delegate.

    From my perspective, you'd need code that will set your app delegate's findContactController to nil when the find contact window is closed. This is not just for garbage-collection. Try opening the find contact window, closing it, and then try opening it again. I theorise that it won't open because findContactController is still set.

    I can't explain off the top of my head why the controllers in your array are being released. How do you know that they are?
     
  12. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #12
    Well that would be very good. Considering the importance of reducing memory leaks, and the common use of opening and closing windows in an application, I would think that there is some boilerplate code out there that does just this. For that matter, the method I use to create and store the window controller is what is used in the books I've learned from, if you know of a better way to create and store windows in your program, then by all means, please share.

    Actually, it does reopen. The reason for that is likely the line below that snippet of initialization.

    Code:
    	[findContactController showWindow:self];
    Simple, I watch the allocation in Instruments. It shows a decrease in both memory usage and the number of living instances of ContactWindowController. This is the reason I am reluctant to completely change the way I create and store the window controllers is the fact that it works in that case.
     
  13. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #13
    I don't think the way you're creating and storing the find contact controller is incorrect. As you demonstrate, even if the window is closed, reusing the old controller is still working.

    I'll get shot by the purists here, but I think that not all memory leaks are a problem.

    If you repeatedly allocate memory that never gets freed so that over time your applications memory footprint continually increases, you have a problem. If you just create one smallish object over the lifetime of a program and it never gets released, then I think you need to weight up the constant footprint increase with the effort to reduce the footprint.

    In this case, if your find contact controller isn't large and doesn't reference other large objects, then the first time your user brings up the find contact window, your application's footprint will increase, but then remain constant. It won't keep increasing over time, even with repeated openings of the window. (Assuming no other memory leaks).

    And you might actually have the potential advantage that if you don't dispose of the window, the window can be in exactly the same state between uses.

    If you want to clean up, put the clean up code in -windowWillClose: of your window's delegate, which is most likely your controller.
     
  14. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #14
    Well, when I open the window for the first time, my program's memory usage jumps by 0.5MB. I don't know, is that a lot for a program that will likely be running for a few hours?

    The clean up code is the real kicker. I'm not sure how to do that. I mean, I can't just put [self dealloc] in the windowWillClose method. Can I?
     
  15. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #15
    No you can't, but that's because you should never explicitly send dealloc to an object. You need to release the remaining reference to your controller in your app delegate by setting it to nil.
     
  16. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #16
    Well, it's less than ideal, but I used the WindowDidClose notification to set the window controller to nil if it matches the class. At the point that I close the window, the # living in Instruments changes from 1 to 0. I would have thought that means that it's released, but I have breakpoints in the -(void)finalize method of my window controller, but the program is never hitting that breakpoint. So what's going on here?
     

Share This Page