2010-06-02 4 views
5

Я недавно заметил крах в одном из моих приложений, когда объект попытался передать сообщение его делегату, и делегат уже был выпущен.Проверка того, был ли объект выпущен перед отправкой ему сообщения

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

if (delegate && [delegate respondsToSelector:...]){ 
    [delegate ...]; 
} 

Но, очевидно, это не учитывает, если делегат не ноль, но было высвобождены.

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

+4

'if (delegate)' is redundant - '[delegate отвечаетsToSelector:]' будет false, если 'delegate' равен нулю. – shosti

+0

Интересные точки. Не думал об этом раньше. –

ответ

16

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

+2

Спасибо. С момента сбоя было просто установить делегат объекта на нуль в dealloc делегата, но мне это казалось вообще :) –

0

как насчет использования счетчика, который вы увеличиваете каждый раз, когда вы выделяете и уменьшаете каждый раз, когда вы освобождаете. Таким образом, вы можете обнаружить двойные распределения и можете решить не использовать делегат, если счетчик isnt nil, но адрес isnt nil также

+0

Это не очень хорошая идея, к сожалению. Объекты отслеживают свой собственный счет удержания, а именно, как они автоматически «освобождаются» после последней версии. Поскольку он не удерживает делегата, это действительно сильно не поможет. –

+0

Да, это был длинный снимок, но я хотел описать, как реферирование и разыменование управляются в фоновом режиме на некоторых фреймах. –

+0

Спустя два года, что @tom спросил, я нахожу его очень полезным. Я столкнулся с тем же сценарием, и лучшим решением было бы объявить свойство моего делегата «слабым», к сожалению, мне нужно сделать его обратно совместимым (также следует поддерживать цели развертывания iOS 4). Поэтому я предполагаю, что это будет работать с блоками вместо шаблона Delegates, будет ли это работать? (Я использую делегатов для загрузки изображений в фоновом режиме и вызова обратного вызова метода делегата после его завершения, я могу сделать то же самое, используя Blocks. Не уверен, что он разрешит проблему за вызовом освобожденных объектов) – chathuram

8

Я предполагаю, что вы не используете GC. В этом случае стандартным соглашением является то, что код, который устанавливает делегат, отвечает за настройку ссылки делегата-пользователя на nil, прежде чем позволить делегату освободиться. Если вы используете GC, вы можете использовать ссылку для делегата __weak, позволяя сборщику мусора установить ссылку на nil, когда экземпляр собран из мусора.

+0

+1 для создания ссылок '__weak' и рекомендации их в контексте GC. На самом деле, можно утверждать, что использование '__weak' в этом случае - это правильная вещь, если (когда?) Код в конечном итоге переключится на GC в будущем. –

+0

все еще существуют __unsafe_unretained для поддержки устаревших, и довольно сложно использовать, поскольку ARC не присваивает значение nil собранным __unsafe_unretained объектам. –

0

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

-(oneway void)release 
{ 
    NSLog(@"release called"); 
    [super release]; 
} 
Смежные вопросы