objective-ccocoacocoa-sheet

Better way to manage lifetime of instance created in class method


In a pet application I'm writing, on the main window, I have a few custom views aligned under each other, each with a label, a combobox and a button.

Clicking the button invokes code that finds the combobox in the same view, and then calls the following function (a class method of RVListEditorController):

+ (void) editComboBox: (NSComboBox *) aComboBox
{
    // Analyze says "possible leak", but both methods ending the panel will release the controller.

    RVListEditorController *controller = [[RVListEditorController alloc] initWithComboBox: aComboBox];

    [NSApp beginSheet: [controller window]
       modalForWindow: [aComboBox window]
        modalDelegate: controller
       didEndSelector: NULL
          contextInfo: nil];
}

The code creates an instance of RVListEditorController. That controls a panel that allows me to edit the list in the combobox (remove items, sort items, etc.). It has, among other controls, two buttons that close it, Cancel and OK.

The code for the two buttons is:

- (IBAction) closeSheetWithOK: (id) sender
{
    [NSApp endSheet: editingPanel];
    [editingPanel orderOut: self];
    [comboBoxValues setArray: valuesCopy];
    if (comboBoxValues.count > 0)
        [editedComboBox setStringValue: [comboBoxValues objectAtIndex: 0]];
    [self release];
}


- (IBAction) closeSheetWithCancel: (id) sender
{
    [NSApp endSheet: editingPanel];
    [editingPanel orderOut: self];
    [self release];
}

These are the only two buttons that close the sheet. My question is about the lifetime management of the instance. It is allocated in the class method, but then control is handed to Cocoa again and the class method ends. The only place I could find to release the instance is in the two handlers for the closing buttons. My problem is that beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo: doesn't simply open the sheet and then waits until it closes again, returning a value how it was closed. If that were the case, I could close the instance in the class method, and I would feel better.

My question: Is there perhaps a better way to handle the lifetime of the instance, or is there something in Cocoa that allows me to open a sheet window-modally and then wait for it to close again, so I could release the instance right after that? I can't think of any, but I am a relative newbie, after all.

FWIW, the code works, so there are no errors. I am simply not very happy with the construct that I allocate something in a class method that must then be released in two instance methods of itself.


Solution

  • I managed to get something that worked to my satisfaction. I provided beginSheet: with a method to be called after the sheet ended, giving controller as the context info. IOW:

        [NSApp beginSheet: [controller window]
           modalForWindow: [aComboBox window]
            modalDelegate: controller
           didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo)
              contextInfo: (void *)controller];
    }
    

    The code for the two buttons is now:

    - (IBAction) closeSheetWithOK: (id) sender
    {
        [comboBoxValues setArray: valuesCopy];
        if (comboBoxValues.count > 0)
            [editedComboBox setStringValue: [comboBoxValues objectAtIndex: 0]];
        [NSApp endSheet: editingPanel];
    }
    
    
    - (IBAction) closeSheetWithCancel: (id) sender
    {
        [NSApp endSheet: editingPanel];
    }
    

    and the code for sheetDidEnd:returnCode:contextInfo: is:

    - (void) sheetDidEnd: (NSWindow *) sheet returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo
    {
        [sheet orderOut: (id)contextInfo];
        [(id)contextInfo release];
    }
    

    That is, IMO, the best that can be done for situations like this. The procedure would have been the same if this had been called from an instance method of the window controller, AFAICT.