Установите делегатов на ноль под ARC?
Я пишу приложения iOS с помощью ARC и настраиваю iOS 5 +.
Предположим, что я пишу пользовательский объект вида, обладающий свойством delegate. При объявлении свойства делегирования я делаю его слабым, чтобы избежать цикла сохранения, так что, когда уничтожается фактический объект-делегат (контроллер), мое пользовательское представление также будет уничтожено следующим образом:
@interface MyCustomView : UIView
@property (nonatomic, weak) id<MyCustomViewDelegate> delegate;
@end
Все хорошо.
Итак, теперь я пишу объект контроллера и ссылается на два объекта представления: мое пользовательское представление и представление UIKit, поставляемое Apple, оба из которых объявляют свойства делегата, а контроллер - делегат для обоих Просмотры. Может быть, это выглядит примерно так:
@interface MyViewController : UIViewController <MyCustomViewDelegate, UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) MyCustomView *customView;
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation MyViewController
- (void)viewDidLoad
{
self.customView.delegate = self;
self.tableView.dataSource = self;
self.tableView.delegate = self;
}
@end
Мой вопрос заключается в следующем: нужно ли переопределить dealloc, чтобы установить либо или оба делегата в nil?
Я имею в виду, как я понимаю, свойство делегирования представления UIKit (в данном случае tableView
) на самом деле не объявлено как слабая ссылка, а скорее ссылкой __unsafe_unretained
, для обратной совместимости с не-ARC-версия iOS. Поэтому, возможно, мне нужно написать
- (void)dealloc
{
_tableView.dataSource = nil;
_tableView.delegate = nil;
}
Теперь, если мне нужно переопределить dealloc, мне все равно не нужно устанавливать _customView.delegate = nil
, правильно? Поскольку это было объявлено (мной) как слабое задание, поэтому оно должно быть установлено на nil автоматически при уничтожении MyViewController
.
Но, с другой стороны, я не нацелен на не-ARC-версии iOS, и не намерен. Так что, возможно, мне вообще не нужно переопределять dealloc?
Ответы
Ответ 1
Настройка слабых делегатов на нуль - это, как правило, хорошая идея, если вы не знаете, что вам не нужно. Для UITableView
и UIScrollView
у меня возникли сбои в предыдущих версиях iOS со следующими шагами (это может помочь запустить с включенными зомби):
- Прокрутите очень быстро.
- Нажмите кнопку "Готово" или кнопку "Назад" или что-то еще, чтобы закрыть VC.
Это похоже на то, что анимация прокрутки сохраняет ссылку на представление, поэтому представление переходит в VC. Он вылетает при отправке события прокрутки.
Я также видел сбои после отклонения VC, содержащего UIWebView
во время загрузки запроса, где просто установка делегата на nil была недостаточной (я думаю, что обходной путь состоял в вызове [webView loadRequest:nil]
).
Ответ 2
Если единственным сильным ссылкой на указанный tableView
является ваш единственный контроллер MyViewController
, вам не нужно вручную устанавливать UITableViewDelegate
или UITableViewDataSource
на nil
.
Причина в том, что после вызова метода dealloc
на вашем MyViewController
табличное представление также будет уничтожено вместе с контроллером (то есть еще раз, пока единственной ссылкой на него является ваш единственный контроллер MyViewController
).
Если у вас есть другие сильные ссылки на эту таблицу, например, другие контроллеры, тогда будет возможно, что табличное представление может существовать дольше, чем класс MyViewController
. В таком случае потребовалось бы установить UITableViewDelegate
и UITableViewDataSource
в nil
в методе dealloc MyViewController
, потому что, как вы упомянули, эти свойства НЕ являются слабыми ссылками и автоматически не будет установлен на nil
.
Однако такая ситуация довольно редко встречается в моем опыте.
В большинстве случаев я не беспокоюсь о том, чтобы установить их на nil
честно, но это защитная практика программирования.
Смотрите также этот пост:
В методе dealloc установлено любое делегирование нуль или не требуется
Ответ 3
Единственная причина, по которой вы хотите явно установить delegate
и dataSource
в nil
, - это то, что customView
или tableView
могут выйти из контроллера просмотра. Установка их в nil
будет защищать от delegate
или dataSource
, ссылающихся на освобожденный объект.
Если customView
и tableView
будут освобождены вместе с контроллером представления, нет необходимости выходить из delegate
и dataSource
.