Удалить делегата на dealloc из объекта, на который нет ссылок - PullRequest
2 голосов
/ 21 января 2010

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

В моем приложении для iPhone у меня есть контроллер вида vc, который выполняет асинхронное действие и отображается как модальное представление. Кнопка отмены отклоняет модальный вид. Если возникает ошибка, отображается UIAlertView alert. Если пользователь нажимает ОК, и alert, и модальное представление исчезают. Поэтому vc установлено как делегат для alert и реализует alertView:didDismissWithButtonIndex:. Примерно так:

// UIViewController vc
    ...
    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"Error"
                          message:@"Something went wrong"
                          delegate:self
                          cancelButtonTitle:@"OK" 
                          otherButtonTitles:nil];
    self.alertView = alert; // needed to unset alertView.delegate in dealloc
    [alert show];
    [alert release];
    ...
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
        [self dismissModalViewControllerAnimated:YES];
    } 
}

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

Я решил это, присвоив alert свойству vc, чтобы я мог установить alert.delegate в ноль в dealloc. Я считаю, что это решение не очень элегантно, потому что мне не нужна ссылка для предупреждения.

Есть ли лучший подход?

Редактировать: Добавлен текст курсивом в качестве пояснения

Ответы [ 4 ]

2 голосов
/ 21 января 2010

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

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

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

Наконец, я думал, что просмотр предупреждений заблокировал весь экранный ввод? Если нет, вы можете сделать его по-настоящему модальным, установив vc.view.userInteractionEnabled = NO, когда появится предупреждение, и переключите его обратно, когда оно будет отклонено. Таким образом, пользователь не может отключить контроллер, пока отображается предупреждение. Что звучит немного более вменяемым для меня.

1 голос
/ 21 января 2010

С точки зрения пользовательского интерфейса, когда присутствует представление предупреждения, оно должно требовать полного внимания пользователя. Возможно, вы могли бы подумать об отключении кнопки «Отмена» (а также любых других видимых виджетов без предупреждения), когда присутствует представление с предупреждением, и добавлении заголовка кнопки в экземпляр UIAlertView, который выполняет ту же задачу. Это обеспечит более понятный пользовательский интерфейс и также должно аккуратно решить проблему с памятью.

0 голосов
/ 21 января 2010

Если вы больше не заботитесь о результатах UIAlertView, вам, вероятно, следует также отклонить его в - (void) viewWillDisappear:(BOOL)animated

0 голосов
/ 21 января 2010
-(void)delayedDismiss {
    [self dismissModalViewControllerAnimated:YES];
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    [self performSelector:@selector(delayedDismiss) withObject:nil afterDelay:0.0];

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