Преобразование самораскрывающихся объектов в ARC - PullRequest
10 голосов
/ 22 февраля 2012

ОК, Apple дала нам ARC, и это здорово. После рефакторинга моего Приложения в ARC почти все работает нормально, и теперь его намного легче разрабатывать и поддерживать.

Есть только одна проблема, которую я до сих пор не могу понять.

Моя программа управления заданиями показывает различную подробную информацию о предложениях, заказах и т. Д. В своих собственных окнах. Поэтому у меня есть специальный класс, в котором WindowControllers выделяется и инициируется с помощью initWithWindowNibName, а затем окно отображается с showWindow:

DetailWindowController *proposalWindowController = [[DetailWindowController alloc] initWithWindowNibName:@"ThePorposalWindow"];
[proposalWindowController showWindow:nil];

До ARC экземпляр WindowController делал релиз, как показано в документации :

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

Но теперь с ARC это больше невозможно, и что еще хуже, в моем специальном классе, где WindowController выделен и инициирован, ARC освобождает тот же windowController, потому что нет указателя на windowController.

Моя идея состояла в том, чтобы скопировать windowController в изменяемый массив:

[proposalWindowArray addObject:proposalWindowController];
[[proposalWindowArray lastObject] showWindow:nil];

А в windowControllers метод делегата windowWillClose я отправляю уведомление своему специальному классу:

- (void)windowWillClose:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ProposalWindowWillClose" object:[[self window] windowController] userInfo:nil];
}

В моем специальном классе я слушаю уведомление и удаляю объект из массива:

- (void) proposalWindowWasClosed: (NSNotification *) notification
{
    [proposalWindowArray removeObjectIdenticalTo:[notification object]];
}

Это работает, но я все еще не верю, что это правильный путь.

У кого-нибудь есть такая же проблема или совет, чтобы сделать его лучше?

Ответы [ 4 ]

10 голосов
/ 07 марта 2012

Я бы, вероятно, использовал делегатский подход, а не уведомления.Обычно лучше иметь внешний объект, который отслеживает открытые окна.Самосохраняющиеся объекты, такие как ваша старая система, нарушают основные принципы владения объектами и затрудняют поиск вещей (например, «дай мне список открытых окон»).Не-синглеты, которые просто «плавают» там, часто возвращаются, чтобы укусить вас в вашей архитектуре (мне пришлось это исправлять достаточно часто).и, в худшем случае, не конец света.Так себе.Единственное отличие состоит в том, что вам нужно делать это явно, а не сопоставлять утечку и перевыпуск (что и делал ваш старый код).

Создайте личное свойство strong.Назначьте self ему.Это создаст цикл сохранения, который будет держать вас, пока вы не установите свойство nil.

0 голосов
/ 15 августа 2014

У меня была такая же проблема, когда я перешел на ARC. Ваше решение работает, но вы делаете его слишком сложным. По сути, вы можете делать то, что делали раньше, выпуская само окно, когда оно закрывается, но совместимым с ARC способом.

Решение состоит в том, чтобы просто создать свойство вашего класса внутри самого класса. Для вашего примера в DetailWindowController вы бы добавили следующее свойство:

@property (strong)  DetailWindowController      *theWindowController;

Затем, когда вы создаете окно с кодом выше, добавьте одну строку примерно так:

DetailWindowController *proposalWindowController = [[DetailWindowController alloc] initWithWindowNibName:@"ThePorposalWindow"];
[preferenceController setTheWindowController:proposalWindowController];
[proposalWindowController showWindow:nil];

Затем, наконец, чтобы ARC освободил окно, когда оно закрыто, как вы делали с предварительным ARC автоматического выпуска в классе DetailWindowController, просто выполните:

- (void)windowWillClose:(NSNotification *)notification
{
    // Let ARC tear this down and clean it up
    [self setTheWindowController:nil];
}
0 голосов
/ 02 марта 2012

Я думаю, что ваш альтернативный подход должен быть правильным, но я не думаю, что вам нужно второе уведомление.Вы должны быть в состоянии сделать:

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

Предполагая, что "offerWindowArray" является статическим NSMutableArray.

0 голосов
/ 22 февраля 2012

Без хаков, нет элегантного способа сохранить объект, кроме как иметь сильную ссылку на него в каком-то другом объекте.Например, вы можете сохранить статический NSMutableArray / NSMutableSet, добавить туда свой контроллер и удалить его в windowsWillClose:.Это будет короче, чем публикация уведомления.Чтобы сделать это повторно используемым, создайте WindowControllerRegistry синглтон с массивом, куда вы добавляете контроллеры, подобные этому, и которые автоматически прослушивают NSWindowWillCloseNotification и удаляют их из своего массива, освобождая таким образом владение.

Какбыстрый обходной путь, вы можете выполнять retain / autorelease звонки из не-ARC файла :

my_retain(self);
my_autorelease(self);

// ArcDisabled.mm
void my_retain(id obj) { [obj retain]; }
void my_autorelease(id obj) { [obj autorelease]; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...