Цель C: где удалить наблюдателя для NSNotification?
у меня есть объективный класс C. В нем я создал метод init и установил в нем NSNotification
//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(getData)
name:@"Answer Submitted"
object:nil];
где я могу установить [[NSNotificationCenter defaultCenter] removeObserver:self] в этом классе? Я знаю, что для UIViewController, Я могу добавить его в viewDidUnload метод Итак, что нужно сделать, если я только что создал класс objective c?
14 ответов:
общий ответ будет "как только вам больше не нужны уведомления". Это явно не удовлетворительный ответ.
Я бы рекомендовал, чтобы вы добавили вызов
[notificationCenter removeObserver: self]методомdeallocиз тех классов, которые вы намерены использовать в качестве наблюдателей, так как это последний шанс отменить регистрацию наблюдателя чисто. Это, однако, защитит вас только от сбоев из-за Центра уведомлений, уведомляющего мертвые объекты. Он не может защитить ваш код от получения уведомлений, когда ваши объекты еще не/уже не в состоянии, в котором они могут правильно обрабатывать уведомления. Для этого... Смотреть выше.Edit (поскольку ответ, похоже, привлекает больше комментариев, чем я думал) все, что я пытаюсь сказать здесь: действительно трудно дать общий совет относительно того, когда лучше всего удалить наблюдателя из центра уведомлений, потому что это зависит:
- в вашем случае использования (какие уведомления наблюдаются? Когда их посылают?)
- реализация наблюдателя (когда он готов получать уведомления? Когда он уже не готов?)
- предполагаемое время жизни наблюдателя (привязано ли оно к какому-либо другому объекту, скажем, к виду или контроллеру вида?)
- ...
Итак, лучший общий совет, который я могу придумать: чтобы защитить ваше приложение. против хотя бы одной возможной неудачи, сделайте
removeObserver:танецdealloc, так как это последняя точка (в жизни объекта), где вы можете сделать это чисто. Это не значит: "просто отложите удаление доdeallocназывается, и все будет хорошо". Вместо этого удалите наблюдателя как только объект больше не готов (или не требуется) для получения уведомлений. Это точно правильный момент. К сожалению, не зная ответов ни на один из упомянутых выше вопросов, я даже не могу предположить, когда этот момент наступит.вы всегда можете безопасно
removeObserver:an объект несколько раз (и все, кроме самого первого вызова с данным наблюдателем будет nops). Итак: подумайте о том, чтобы сделать это (снова) вdeallocпросто чтобы быть уверенным, но в первую очередь: сделать это в подходящий момент (что определяется в вашем случае).
Примечание : это было проверено и работает на 100% процентов
Свифт
override func viewWillDisappear(animated: Bool){ super.viewWillDisappear(animated) if self.navigationController!.viewControllers.contains(self) == false //any other hierarchy compare if it contains self or not { // the view has been removed from the navigation stack or hierarchy, back is probably the cause // this will be slow with a large stack however. NSNotificationCenter.defaultCenter().removeObserver(self) } }PresentedViewController
override func viewWillDisappear(animated: Bool){ super.viewWillDisappear(animated) if self.isBeingDismissed() //presented view controller { // remove observer here NSNotificationCenter.defaultCenter().removeObserver(self) } }С
на
iOS 6.0 > version, его лучше удалить наблюдателя вviewWillDisappearкакviewDidUnloadметод устарел.[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
есть много раз лучше
remove observerкогда вид был удален из окнаnavigation stack or hierarchy.- (void)viewWillDisappear:(BOOL)animated{ if (![[self.navigationController viewControllers] containsObject: self]) //any other hierarchy compare if it contains self or not { // the view has been removed from the navigation stack or hierarchy, back is probably the cause // this will be slow with a large stack however. [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere]; } }PresentedViewController
- (void)viewWillDisappear:(BOOL)animated{ if ([self isBeingDismissed] == YES) ///presented view controller { // remove observer here [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere]; } }
с iOS 9 больше не нужно удалять наблюдателей.
в OS X 10.11 и iOS 9.0 NSNotificationCenter и NSDistributedNotificationCenter больше не будет отправлять уведомления зарегистрированные наблюдатели, которые могут быть освобождены.
если наблюдатель добавляется к посмотреть контроллер, я настоятельно рекомендую добавить его в
viewWillAppearи удаление его вviewWillDisappear.
в swift используйте deinit, потому что dealloc недоступен:
deinit { ... }Swift документация:
деинициализатор вызывается непосредственно перед экземпляром класса освободившему. Вы пишете deinitializers с ключевым словом deinit, похожие как инициализаторы пишутся с сайта инит. Деинитализаторы доступны только для типов классов.
обычно вам не нужно выполнять ручную очистку, когда ваш экземпляры освобождаются. Однако, когда вы работаете с вашим собственным ресурсов, возможно, потребуется выполнить некоторые дополнительные очистки себе. Например, если вы создадите пользовательский класс для открытия файла и напишите некоторые данные к нему, вы могли закрыть архив перед экземпляр класса освобождается.
*edit: этот совет относится к iOS viewWillAppear и удаление в
viewWillDisappear- однако Совет применяется, если по какой-то причине вы добавили наблюдателя вviewDidLoad)если вы добавили наблюдателя в
viewDidLoadвы должны удалить его какdeallocиviewDidUnload. В противном случае вы будете в конечном итоге добавить его дважды, когдаviewDidLoadвызывается послеviewDidUnload(это произойдет после предупреждения памяти). Это не обязательно в iOS 6, гдеviewDidUnloadустарел и не будет вызываться (потому что представления больше не выгружаются автоматически).
на мой взгляд, следующий код не имеет смысла в ARC:
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; }на iOS 6, также нет смысла удалять наблюдателей в
viewDidUnload, потому что он уже устарел.подводя итог, я всегда делаю его в
viewDidDisappear. Однако это также зависит от ваших требований, как и сказал @Dirk.
Я думаю, что нашел достоверный ответ! Мне пришлось, так как ответы выше неоднозначны и кажутся противоречащими. Я просмотрел кулинарные книги и руководства по программированию.
во-первых, стиль
addObserver:наviewWillAppear:иremoveObserver:наviewWillDisappear:не работает для меня (я тестировал его), потому что я отправляю уведомление в дочернем контроллере представления для выполнения кода в Родительском контроллере представления. Я бы использовал этот стиль только в том случае, если бы я публиковал и слушал уведомление в пределах того же контроллера вида.ответ, на который я буду полагаться больше всего, я нашел в программировании iOS: Big Nerd Ranch Guide 4th. Я доверяю ребятам из БНР, потому что у них есть учебные центры iOS, и они не просто пишут еще одну поваренную книгу. Вероятно, в их интересах, чтобы быть точным.
БНР один пример:
addObserver:наinit:,removeObserver:наdealloc:БНР пример второй:
addObserver:наawakeFromNib:,removeObserver:наdealloc:...когда удаление наблюдателя в
dealloc:они не используют[super dealloc];я надеюсь, это поможет следующему человеку...
Я обновляю этот пост, потому что Apple теперь почти полностью ушла с раскадровками, поэтому вышеупомянутое может не относиться ко всем ситуациям. Важно (и причина, по которой я добавил этот пост в первую очередь), чтобы обратить внимание, если ваш
viewWillDisappear:- это вызов. Это было не для меня, когда приложение вошло в фоновом режиме.
принятый ответ не является безопасным и может привести к утечке памяти. Пожалуйста, оставьте отмену регистрации в dealloc, но также отмените регистрацию в viewWillDisappear (это, конечно, если вы регистрируетесь в viewWillAppear)....ЭТО ТО, ЧТО Я СДЕЛАЛ В ЛЮБОМ СЛУЧАЕ, И ЭТО ОТЛИЧНО РАБОТАЕТ! :)
важно также отметить, что
viewWillDisappearвызывается также, когда контроллер представления представляет новый UIView. Этот делегат просто указывает, что основной вид контроллера вида не отображается на дисплее.в этом случае освобождение уведомления в
viewWillDisappearможет быть неудобно, если мы используем уведомление, чтобы разрешить UIview общаться с контроллером родительского вида.в качестве решения я обычно удаляю наблюдателя в одном из этих двух методы:
- (void)viewWillDisappear:(BOOL)animated { NSLog(@"viewController will disappear"); if ([self isBeingDismissed]) { NSLog(@"viewController is being dismissed"); [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil]; } } -(void)dealloc { NSLog(@"viewController is being deallocated"); [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil]; }по аналогичным причинам, когда я выдаю уведомление в первый раз, мне нужно учитывать тот факт, что в любое время вид с появляется над контроллером, то
viewWillAppearметод срабатывает. Это, в свою очередь, создаст несколько копий одного и того же уведомления. Поскольку нет способа проверить, если уведомление уже активно, я устраняю проблему, удаляя уведомление перед его добавлением:- (void)viewWillAppear:(BOOL)animated { NSLog(@"viewController will appear"); // Add observers [[NSNotificationCenter defaultCenter] removeObserver:self name:@"imageGenerated" object:nil]; // This is added to avoid duplicate notifications when the view is presented again [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedImageFromCameraOrPhotolibraryMethodOnListener:) name:@"actionCompleted" object:nil]; }
SWIFT 3
есть два случая использования уведомлений: - они нужны только тогда, когда контроллер представления на экране; - они нужны всегда, даже если пользователь открыл другой экран по току.
в первом случае правильное место для добавления и удаления наблюдателя:
/// Add observers /// /// - Parameter animated: the animation flag override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(...) } /// Remove observers /// /// - Parameter animated: the animation flag override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) }для второго случая правильный путь:
/// Add observers override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(...) } /// Remove observers /// /// - Parameter animated: the animation flag override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if self.isBeingDismissed // remove only when view controller is removed disappear forever || !(self.navigationController?.viewControllers.contains(self) ?? true) { NotificationCenter.default.removeObserver(self) } }и никогда не ставить
removeObserverнаdeinit{ ... }- это ошибка!
override func viewDidLoad() { //add observer super.viewDidLoad() NotificationCenter.default.addObserver(self, selector:#selector(Yourclassname.method), name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil) } override func viewWillDisappear(_ animated: Bool) { //remove observer super.viewWillDisappear(true) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil) }
Comments