Подтвердить что ты не робот

Кто владеет NSWindowController, в стандартной практике?

Я ищу дальнейшие разъяснения после просмотра Что несет ответственность за выпуск объектов NSWindowController?

Я пишу простое приложение для управления запасами для своих племянников. У меня есть табличное представление, отображающее содержимое их "библиотеки" и т.д. Чтобы добавить новый элемент в библиотеку, они нажимают кнопку "+". Эта кнопка открывает новое окно с запросом деталей элемента и проверяет ввод, когда они нажимают "OK".

Все это работает отлично. Однако у меня есть вопрос об управлении памятью. Чтобы создать новое окно, я использую следующий код:

- (IBAction)addNewItem:(id)sender {
  LibraryItemEditorController *editorController = 
    [[LibraryItemEditorController alloc] 
          initWithWindowNibName:@"LibraryItemEditor"];

  [editorController showWindow:nil];
  // editorController is "leaked" here, it seems.
}

Я не могу освободить (и не авторекламу) editorController в конце addNewItem:, потому что ничего не ссылается на editorController; если я его отпущу, окно сразу исчезнет. Тем не менее, я хочу, чтобы оконный контроллер был освобожден после закрытия его окна. В Apple Руководство по программированию окон, я прочитал следующее:

Если вы хотите закрыть окно, чтобы сделать как оконный, так и оконный контроллер уйти, когда он не является частью документ, ваш подкласс NSWindowController может наблюдать NSWindowWillCloseNotification или, как делегат окна, выполните windowWillClose: и включить следующая строка кода в вашем реализация:

[self autorelease];

Я использовал [self autorelease] в методе windowWillClose: контроллера окна. Это работает и не утечки памяти. Однако он просто чувствует себя некрасиво; addNewItem: выглядит как утечка памяти, и статический анализ тоже так думает. Я знаю, что он действительно заботился о windowDidClose:, но он просто чувствует себя не так. Кроме того, оконный контроллер теперь освобождает себя, не сохранив при этом себя. Все это противоречит правилам управления памятью, которые я узнал.

Моя другая опция - поставить ivar на родительский контроллер (либо NSWindowController, либо NSMutableSet of NSWindowController s), а затем посмотреть на NSWindowWillCloseNotification в родительском контроллере и отпустить его в ответ. Это чище, и, вероятно, я это сделаю. Тем не менее, это еще и большая работа, что приводит меня к моим вопросам.

Наблюдает за стандартным способом NSWindowDidCloseNotification? Каков стандартный способ управления NSWindowControllers, который создается и уничтожается по требованию? Является ли метод [self autorelease] традиционно рекомендованным, и только теперь, когда у нас есть статический анализ, это проблема?

4b9b3361

Ответ 1

Похоже, ваше окно модально, и в этом случае:

[NSApp runModalForWindow:[editorController window]];
[editorController release];

Здесь один шаблон для немодальных окон:

@implementation QLPrefWindowController

+ (id) sharedInstance
{
    if (!_sharedInstance)
    {
        _sharedInstance = [[QLPrefWindowController alloc] init];
    }
    return _sharedInstance;
}

- (void)windowWillClose:(NSNotification *)notification
{
    if ([notification object] == [self window] && self == _sharedInstance)
    {
        _sharedInstance = nil;
        [self release];
    }
}

Тогда любой, кто хочет получить доступ или отображает окно, может сделать это с помощью метода класса +sharedInstance. Если окно уже не видно, оно создается, иначе они получают окно, отображаемое в настоящее время.

Ответ 2

Решение для немодальных ситуаций, описанных выше, неверно, потому что методы класса не могут обращаться к iVars. Я решил эту проблему, создав метод класса (в моем подклассе NSWindowController под названием LPWindowController), который выглядит так:

+ (id) autoreleasingInstanceShowingWindow
{
    LPWindowController *obj = [[LPWindowController alloc] initWithWindowNibName:@"myWindow"];
    [obj showWindow:[NSApp delegate]];

    return obj; 
}

Вышеуказанный метод возвращает экземпляр LPWindowController со значением удержания 1. Он также показывает окно контроллера. Это важно, потому что в противном случае нам придется полагаться на вызывающего абонента, чтобы вызвать "showWindow:", чтобы отобразить окно LPWindowController. Если вызывающий абонент когда-либо не смог этого сделать (что, вероятно, было бы ошибкой), контроллер никогда не будет выпущен. Заставляя окно отображать, когда мы выделяем/запускаем контроллер, мы избегаем этой ошибки.

Затем, в IB, мы устанавливаем делегат окна в класс LPWindowController и добавляем его в этот класс:

- (void) windowWillClose:(NSNotification *)notification
{
    [self autorelease];
}

И, наконец, когда нам нужно создать и показать наше окно, мы просто используем метод ниже вместо вызова "alloc/initWithWindowNibName:" на LPWindowController.

LPWindowController *cont = [LPWindowController autoreleasingInstanceShowingWindow];
cont = nil;

Вторая строка важна. Во-первых, он устраняет предупреждение о "неиспользованной переменной cont". Во-вторых, он устраняет опасность свисающего указателя. Как только экземпляр LPWindowController освободится, если cont не завершен, он укажет на память мусора.

В любом случае, мой рекомендуемый подход к этой проблеме.