Объект Objective-C, находящийся в состоянии освобождения, в то время как другие объекты все еще имеют ссылку на делегат, вызывает сбои. Как это предотвратить? - PullRequest
0 голосов
/ 09 апреля 2011

У меня есть приложение с контроллером навигации в качестве корневого представления. Есть много взглядов, которые можно подтолкнуть. Пользователь должен создать учетную запись, чтобы использовать приложение. Затем пользователь может войти в эту учетную запись с других устройств, но одновременно на одну и ту же учетную запись можно войти только с одного устройства. Поэтому, если несколько устройств пытаются войти в учетную запись, только последнее устройство будет зарегистрировано, а другие устройства отключены (на устройства отправляется push-уведомление).

Поскольку существует несколько представлений, которые устройство могло отображать до выхода из системы, я вызываю popToRootViewControllerAnimated: для возврата к корневому представлению. Это связано с тем, что при следующем входе пользователя в систему я хочу, чтобы отображался только корневой вид (новая учетная запись может не иметь доступа к ранее показанному представлению).

Если пользователь получил представление оповещения или лист действий (который использует текущее представление в качестве своего делегата) до получения нажатия, представление все равно будет отображаться после вызова метода popToRootViewControllerAnimate: Если пользователь затем нажимает кнопку для просмотра предупреждений или листа действий, он отправляет сообщение на просмотр dealloc и завершает работу приложения.

Пример: myViewController показывается пользователю. myViewController создает лист действий, предлагающий пользователю принять решение. Подтверждение получено для выхода устройства. Контроллер навигации выводит все контроллеры представлений и теперь показывает myRootViewController. Так как контроллеры представления вытолкнуты, myViewController теперь освобожден. Лист действий из myViewController по-прежнему отображается. Когда пользователь выбирает опцию из листа действий, в myViewController отправляется сообщение, и, поскольку оно уже освобождено, происходит сбой.

Есть ли способ предотвратить это?

Одним из решений, которое я рассмотрел, было бы отслеживать все объекты, которые используют определенный контроллер представления в качестве своего делегата. Затем, когда этот контроллер представления dealloc's, он также установит все делегаты объекта равными nil. Для этого мне нужно вручную позаботиться о каждом контроллере представления, когда он создает объект, который использует себя в качестве делегата, поскольку я не могу придумать способ автоматического создания и обновления этого списка.

Любое лучшее решение (или улучшение моего) будет оценено!

Редактировать: Представление предупреждений и лист действий являются лишь примерами некоторых объектов, которые я использовал бы в качестве делегата myViewController. Я также использую ряд других классов (и сторонних библиотек), которые реализуют этот шаблон делегата.

Ответы [ 3 ]

1 голос
/ 09 апреля 2011

Несколько идей:

  1. вы можете инкапсулировать представление листа предупреждения / действия и делегировать его в один класс. Затем, когда вам понадобится представление предупреждений, вместо этого создайте MyAlertView, который также будет собственным делегатом и выполнит [самоотключение] после того, как пользователь нажмет кнопку.

  2. делает ваше приложение Delegate единственным делегатом для всех ваших просмотров предупреждений и листов действий. Делегат приложения всегда присутствует во время работы приложения, поэтому с освобожденным делегатом проблем не возникнет.

Проблема с обоими решениями заключается в том, что если вам нужно, чтобы ваше приложение знало, что произошло в окне просмотра / действия предупреждений, вам нужно как-то сообщить заинтересованному классу о выборе пользователя.

Вы можете сделать это либо с помощью своих собственных делегатов - что будет означать, что вы вернулись на круги своя, либо с помощью уведомлений: когда вызывается делегат вида оповещения / листа действий, он отправляет уведомление ([[NSNotificationCenter defaultCenter] postNotificationName:NotificationName object:self userInfo:userInfo]; ), в то время как заинтересованный объект будет искать это уведомление ([[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNotification:) name:NotificationName object:nil];) и выполнять любые задачи, необходимые в методе onNotification:(NSNotification*)aNotification.

Вы сможете сами договориться о том, какой тип информации передается в этих уведомлениях (я думаю, что номера кнопки в классе NSNumber будет достаточно, или, возможно, также пропустите текст кнопки). И вам не нужно будет отслеживать все оповещения о взглядах - просто не забудьте удалить наблюдателя ([[NSNotificationCenter defaultCenter] removeObserver:self name:postNotificationName object:nil];) в dealloc представлений.

Редактировать:

«Для этого мне нужно вручную позаботиться о каждом контроллере представления при создании объекта, который использует себя в качестве делегата, поскольку я не могу придумать способ автоматического создания и обновления этого списка».

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

-(id)delegate:(id)delegate for:(id)forWhom

А потом вместо

someThingy.delegate = self;

вы бы сделали

someThingy.delegate = [[DelegateLocker defaultLocker] delegate:self for:someThingy];

Внутри DelegateLocker у вас будет MutableDictionary с классом делегата в качестве ключа и MutableArray для someThingies в качестве значения. Тогда, по вашему мнению, триллоки контроллеров вы бы назвали

[[DelegateLocker defaultLocker] delegateIsDying:self];

, который прошел бы через штуковину и назначил делегат = ноль для каждого

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

0 голосов
/ 09 апреля 2011

Если вам нужно автоматизированное решение, я думаю, что вы можете создать функцию для перебора Ivars вашего контроллера представления, чтобы увидеть, есть ли у любого Ivar свойство delegate и установить его в nil.

0 голосов
/ 09 апреля 2011

Итак, ViewController, представивший лист действий, и установил себя в качестве делегата, верно?Так почему бы вам не сохранить ссылку на ActionSheet в ViewController, в методе dealloc контроллера представления вы можете проверить, виден ли лист действия, установлен ли он тогда для делегата листа действия, и отклонить его....

так

-(void)dealloc
{
   if(myActionSheet && [myActionSheet visible])
   {
      [myActionSheet setDelegate: nil];
      //dismiss 
    }

}

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...