2009-12-20 3 views
2

Я новичок в Mac Dev. Я пришел из iPhone dev. Мой вопрос касается немодального управления окнами. Это сильно отличается от iPhone и его модели управления памятью.Управление памятью немодальных окон

Скажет, например, у меня есть окно предпочтений, я могу использовать что-то вроде этого, чтобы показать окно:

-(IBAction)showPreferenceController:(id)sender { 
    if (!preferenceController) { 
    preferenceController = [[PreferenceController alloc]init]; 
    } 
    [preferenceController showWindow:preferenceController]; 
} 

Но с этим кодом, окно будет оставаться в памяти во время приложения жизни, потому что окно никогда не выпускался.

Чтобы избежать этого, я мог бы также использовать метод, описанный здесь:
stackoverflow.com/questions/1391260/who-owns-an-nswindowcontroller-in-standard-practice
Создание в PreferenceController с + (id) sharedInstance и отпустить окно с использованием (void)windowWillClose:(NSNotification *)notification

Я вижу множество примеров кода какао, где не модальные окна никогда не выпускаются. Например: http://www.mattballdesign.com/blog/2008/10/01/building-a-preferences-window/: Панель предпочтений и все подземелья создаются в awakeFromNib и поэтому будут жить в памяти в течение всей жизни приложения.

Если взять, например, Xcode приложения, есть много покадровых окна:
- Глобальное окно Find (CMD + МАЙ + F)
- App Info Panel
- Окно справки
-. ..

Я полагаю, что эти окна выпускаются, когда они закрыты, чтобы сохранить память как можно ниже. Я бы хотел, чтобы некоторые советы знали, как лучше управлять немодальными окнами в приложении для какао. Хранить в памяти? Освобождение как можно скорее? Я знаю, что у Mac много памяти по сравнению с iPhone, но я также считаю, что не стоит хранить в объектах памяти, которые мы не используем.

Спасибо.

Отредактировано с Робом пост:

Я посылаю -autorelease к окну и установить мой указатель на ноль, так что я буду воссоздать окно позже. Это похоже на технику, которую вы цитируете, но независимо от того, следует ли использовать + sharedController для контроллера, не имеет отношения; вы можете это сделать, если у вас есть общий контроллер или нет.

Я не могу это сделать без синглета (+ sharedController).
я объясню, что я имею в виду с этим примером:
В App Controller:

@interface AppController : NSObject <NSApplicationDelegate> { 

Реализация:

-(IBAction)showPreferenceController:(id)sender { 
    if (!preferenceController) { 
    preferenceController = [[PreferenceController alloc]init]; 
    } 
    [preferenceController showWindow:preferenceController]; 
} 

В контроллере предпочтений:

@interface PreferenceController : NSWindowController <NSWindowDelegate> 

Реализация:

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

Он сработает, когда я закрою и снова откроюсь после окна: preferenceController освобожден, но не равен нулю. Поэтому, когда окно закрывается, мне нужно установить preferenceController на нуль. Нет проблем с этим синглом.
Без singleton я должен установить appController в качестве делегата окна предпочтений, чтобы иметь возможность устанавливать preferenceController на нуль, когда окно закрыто. Но мне это не нравится.

Отредактировано с Престоном комментарии
Я не говорил, но я хочу только один экземпляр моей покадрово окна, даже если мы называем -(IBAction)showPreferenceController:(id)sender несколько раз.
Вот почему я тестирую, если preferenceController равен нулю или нет в appController.
Итак, мне нужно установить preferenceController на nil в appController, если мы закроем окно.
Таким образом, решение будет:
В AppController, слушая NSWindowWillCloseNotification:

- (void)windowWillClose:(NSNotification *)notification { 
    if ([notification object] == [preferenceController window]) { 
     [preferenceController autorelease]; 
     preferenceController = nil; 
    } 
} 

Является ли это правильно? Это единственное решение? потому что это кажется немного сложным, просто для управления моим немодным окном ...

+1

Вы не должны выпускать «я» здесь (вы почти никогда не должны называть [self release]). Вы должны освобождать self.window и устанавливать self.window = nil. –

+1

Кроме того, я бы рекомендовал это быть «[self.window autorelease]; self.window = nil; ' Таким образом, окно может завершить закрытие до того, как оно будет выпущено. –

+0

Спасибо, Роб, мой пример был только для того, чтобы объяснить проблему, потому что, как сказано, пример приведет к сбою. Я хочу установить preferenceController в nil, и это должно быть реализовано в appController. Я редактировал свой вопрос с вашими последними комментариями. – Benoit

ответ

3

Вы думаете, что здесь все правильно. Неплохо просачивать память, потому что у вас ее много. Тем не менее, обычно не выпускать окна только потому, что они закрываются на Mac. Обычно вы должны держать их, если думаете, что их снова откроют, чтобы избежать их перезарядки.

Существует две школы мысли на NSWindow: принадлежит и не используется. Я из «принадлежащей» школы мысли. Обычно я предоставляю каждому окну владельцу, который сохраняет его с помощью ivar и выпускает его, когда это необходимо. Как правило, это делегат, иногда это контроллер приложения. В -windowShouldClose: я посылаю -autorelease в окно и устанавливаю указатель на нуль, поэтому позже я закрою окно. Это похоже на технику, которую вы цитируете, но не имеет значения, следует ли использовать +sharedController для Контроллера; вы можете это сделать, если у вас есть общий контроллер или нет.

Неудачная школа мысли заключается в использовании NSWindow's -setReleasedWhenClosed:, так что она автоматически освобождается, когда она закрывается. Я считаю, что некоторые из окон, на которые вы ссылаетесь, делают это так, когда они предоставляются системой, поскольку не может быть делегата. Это может быть полезно для некоторых типов панелей, но я буду осторожен с ним в качестве общей схемы. Лучше иметь явное управление памятью практически во всех случаях.

+0

Спасибо, Роб, мне лучше понять управление окнами. Я отредактировал свой вопрос после вашего сообщения, потому что я не понимаю, как выпустить окно без объекта singleton. – Benoit

1

Если вы установите флажок «Освобождение при закрытии» для вашего окна в Interface Builder или установите его программно, он освободится.Вы также можете включить делегат окна в окно windowShouldClose: delegate.

Если вы хотите освободить оконный контроллер, когда окно закрывается, попросите оконный контроллер прослушать NSWindowWillCloseNotification своего окна и выполнить [self autorelease] в этом методе. Я не поклонник создания контроллера предпочтений singleton, который всегда придерживается того, что на практике пользователь будет редко взаимодействовать.

+1

Спасибо. В справке Xcode для setReleasedWhenClosed «Release when closed», однако, игнорируется для окон, принадлежащих оконным контроллерам ». Это мое дело. В моем вопросе я приведу пример с autorelease в «windowWillClose». Но проблема в том, что я хочу ТОЛЬКО ОДНО окно, даже если мы будем называть это окно несколько раз. Вот почему я тестирую, если preferencesController равен нулю или нет в методе showPreferenceController. Поэтому, когда окно закрывается, мне нужно установить preferenceController. Затем я должен слушать NSWindowWillCloseNotification в appController, а не в preferencesController. Верно или нет? – Benoit

+0

Я отредактировал свой вопрос с вашего комментария, чтобы найти лучшее решение. – Benoit

+0

А, вы правы в том, что поведение в выпуске окон. Я имел в виду глобальный одноэлементный объект, а не обычную переменную экземпляра. После выделения объект singleton не освобождается до завершения приложения. Да, у вас может быть объект, которому принадлежит ваш контроллер настроек, прослушивание уведомления о закрытии окна и просто автоопределение контроллера предпочтений, за которым следует установка переменной экземпляра в nil. Контроллер настроек освободит окно, которому он владеет. Если использование памяти этой вещи является для вас большой проблемой, я бы это сделал. – 2009-12-28 19:01:38