NSNotification и didReceiveMemoryWarning в iOS 6

Начиная с iOS 6.0, метод viewDidUnload устарел. До iOS 6 я использовал метод removeObserver NSNotification в методе viewDidUnload. Но поскольку он устарел, я переместил его в didReceiveMemoryWarning. Теперь, если мое приложение получает предупреждение о нехватке памяти, уведомление удаляется. Так что мой код, написанный в NSNotification, не работает.

Может ли кто-нибудь сказать мне, как я могу решить эту проблему?

Заранее спасибо.


person iOSAppDev    schedule 20.04.2013    source источник


Ответы (2)


Я предполагаю, что вы добавили наблюдателя в viewDidLoad. Проблема в том, что на iOS 6 представления не выгружаются даже при нехватке памяти. Поэтому, если вы удалите наблюдателя в didReceiveMemoryWarning, viewDidLoad больше вызываться не будет.

Есть две относительно простые альтернативы, которые вы можете выбрать:

  • Добавьте наблюдателя в viewWillAppear и удалите его в viewWillDisappear.
  • Добавьте наблюдателя в свой метод initXXX и удалите его в dealloc.

Возможно добавить наблюдателя в viewDidLoad и удалить его в didReceiveMemoryWarning. Но тогда вам придется «вручную выгрузить» представление в didReceiveMemoryWarning, чтобы viewDidLoad потом снова вызывалось. См., например. https://stackoverflow.com/a/15805715/1187415 для примера кода, как принудительно выгрузить представление.

person Martin R    schedule 20.04.2013
comment
Спасибо за ответ. Я могу следовать первому варианту, так как мне нужны уведомления во время работы приложения. Могу ли я добавить наблюдателя в viewDidLoad и удалить его в методе Dealloc? Спасибо - person iOSAppDev; 20.04.2013
comment
@iOSAppDev: Да, но вы должны установить флаг, был ли добавлен наблюдатель или нет, потому что 1) Dealloc может быть вызван без предварительного вызова viewDidLoad, 2) если вы позже перепишете свой код, чтобы принудительно выгрузить представление, viewDidLoad будет снова позвонил. Но количество вызовов addObserver/removeObserver должно точно совпадать. - person Martin R; 20.04.2013
comment
Из вашего комментария я понимаю, что мне нужно добавить один флаг, скажем, isObserverRemovedForNotification. Я установлю это в Dealloc. Итак, в viewDidLoad я проверю if(isObserverRemovedForNotification) { // Add observer for notification } Правильно ли это? Также могу ли я написать метод Dealloc с ARC? - person iOSAppDev; 20.04.2013
comment
@iOSAppDev: Вы не должны добавлять наблюдателя дважды, но я бы сделал наоборот: if (!isObserverAdded) { isObserverAdded = YES; ... add observer }. Но то, что newacct сказал в своем ответе, также верно: вы можете добавить наблюдателя в viewDidLoad и удалить его в viewDidUnload + Dealloc. - И да, вполне нормально написать метод Dealloc в ARC. Только не звони [super dealloc]. - person Martin R; 20.04.2013
comment
Но в iOS 6 метод viewDidUnload устарел. Поэтому он создает предупреждения в проекте. - person iOSAppDev; 20.04.2013
comment
В iOS 6 (как правильно сказал newacct) представление никогда не будет выгружено, а viewDidUnload никогда не будет вызываться (если вы не заставите его, как в ссылке, которую я дал). Поэтому, если ваша цель развертывания = 6.0, вы можете добавить наблюдателя в viewDidLoad и удалить его в Dealloc, viewDidLoad будет вызываться только один раз. - Если вы установите цель развертывания на 5.0, то может быть вызван viewDidUnload, и вы можете использовать его для удаления наблюдателя. - В качестве альтернативы вы можете использовать viewWillAppear/viewWillDisappear. - person Martin R; 20.04.2013
comment
Спасибо Мартин за вашу помощь. Я очень ценю это. - person iOSAppDev; 20.04.2013

Проблема в том, что вы совершенно не понимаете, что означает viewDidUnload. viewDidUnload вызывается, когда представление выгружается. В версиях до iOS 6, когда вы заканчивали работу с контроллером представления, его представление НЕ выгружалось. В версиях, предшествующих iOS 6, в 99 % случаев вы никогда не увидите, как выполняется viewDidUnload, потому что представления обычно не выгружаются. В версиях до iOS 6 представления выгружались только в ответ на предупреждение о памяти, и представление не отображалось. В iOS 6 единственным изменением является то, что представления никогда не выгружаются, даже при предупреждении о памяти.

Поведение viewDidUnload идентично в версиях до iOS 6 и iOS 6 — оно вызывается при выгрузке представления. Из-за этого вам НЕ нужно менять какой-либо код для iOS 6. Если вы это сделаете, вы сделали что-то не так.

До iOS 6 я использовал метод removeObserver NSNotification в методе viewDidUnload.

Если вы имеете в виду, что добавили наблюдателя в viewDidLoad, то вы должны удалить его в dealloc. В противном случае ваш код рухнет. Как я уже говорил выше, в 99% случаев в версиях до iOS 6 представления не выгружались. Типичный поток: init -> viewDidLoad -> dealloc. Представление не разгружается посередине.

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

Итак, ответ таков: вам не нужно ничего менять в ответ на iOS 6. Все, что вы сделали в viewDidLoad, должно быть отменено как в viewDidUnload (необязательно), так и в dealloc (обязательно). Это верно как для iOS 6, так и для iOS 6.

person newacct    schedule 20.04.2013
comment
Спасибо за ответ . Согласно вашему ответу, я могу добавить наблюдателя в viewDidLoad и удалить его в методе Dealloc, верно? Могу ли я написать метод Dealloc с помощью ARC? - person iOSAppDev; 20.04.2013