DidReceiveMemoryWarning, viewDidUnload и dealloc
Я просмотрел множество сообщений, моих книг и Apple Developer и получил большую часть понимания, которое мне нужно использовать. Я был бы очень благодарен, если какой-нибудь человек может подтвердить, что у меня все в порядке (или исправить), а также ответить на два вопроса.
Большое спасибо,
Крис.
Порядок сообщений
Как правило, сообщения отображаются в следующем порядке:
didReceiveMemoryWarning
Вызывается, когда система неактивна в памяти.
По умолчанию контроллеры просмотра регистрируются для уведомлений о предупреждении памяти и в методе шаблона, вызов [super didReceiveMemoryWarning] освобождает представление, если у него нет супервизора, что является способом проверки видимости вида или нет. Он освобождает представление, устанавливая его свойство равным нулю.
Действие. Отпустите все, что вам не нужно, скорее всего, будет уничтожено то, что вы могли установить в viewDidLoad. Не выпускайте элементы пользовательского интерфейса, поскольку они должны быть выпущены функцией viewDidUnload.
Question1 - Кажется, что это будет вызвано, даже если вид виден, поэтому его трудно увидеть, что вы можете спокойно освободить. Было бы очень полезно понять это и некоторые примеры того, что может быть выпущено.
viewDidUnload
Вызывается всякий раз, когда для невидимого свойства View Controller View установлено значение nil, либо вручную, либо чаще всего через didReceiveMemoryWarning.
Метод viewDidUnload существует, чтобы вы могли:
- очистить все остальное, что вы хотели бы, чтобы сохранить дополнительную память или
- если вы сохранили некоторые IBOutlets, чтобы освободить память, которая иначе не была бы выпущена при разгрузке представления.
Действие - как правило, любые IBOutlets, которые вы выпускаете в dealloc, также должны быть освобождены (и ссылки установлены на нуль) в этом методе. Обратите внимание, что если свойства будут сохранены, то их установка будет равна нулю.
dealloc
Вызывается, когда объект контроллера просмотра де-распределен, что будет, когда счетчик удержания падает до нуля.
Действие - освободить все объекты, сохраненные классом, включая, но не ограничиваясь, все свойства с сохранением или копированием.
Контроллеры просмотров и памяти
Вопрос 2 - Выводит ли вид снимок из памяти?
Ответы
Ответ 1
Некоторые исправления и предложения:
-
didReceiveMemoryWarning
практики
Как вы сказали, реализация по умолчанию контроллера didReceiveMemoryWarning
освобождает его представление, если оно "безопасно". Хотя из документов Apple не ясно, что означает "безопасно это сделать", оно общепризнано, поскольку оно не имеет супервизора (таким образом, в настоящее время нет видимого представления), а его метод loadView
может перестроить весь вид без проблем.
Лучшая практика при переопределении didReceiveMemoryWarning
заключается в том, чтобы не пытаться вообще отпускать какие-либо объекты просмотра. Просто отпустите свои пользовательские данные, если они больше не нужны. Что касается представлений, просто разрешите реализацию суперкласса с ними.
Иногда, однако, необходимость данных может зависеть от состояния вашего представления. В большинстве случаев эти пользовательские данные устанавливаются в методе viewDidLoad
. В этих случаях "безопасный выпуск пользовательских данных" означает, что вы знаете, что loadView
и viewDidLoad
будут вызваны до того, как контроллер просмотра снова будет использовать пользовательские данные.
Поэтому в вашем didReceiveMemoryWarning
сначала вызовите реализацию суперкласса, и если его представление будет выгружено, отпустите пользовательские данные, потому что вы знаете, что loadView
и viewDidLoad
будут снова вызваны. Например,
- (void)didReceiveMemoryWarning {
/* This is the view controller method */
[super didReceiveMemoryWarning];
if (![self isViewLoaded]) {
/* release your custom data which will be rebuilt in loadView or viewDidLoad */
}
}
Соблюдайте осторожность, чтобы не использовать self.view == nil
, потому что self.view
предполагает, что представление необходимо кому-то и немедленно загрузит представление.
viewDidUnload
вызывается, когда контроллер просмотра выгружает представление из-за предупреждения о памяти. Например, если вы удалите представление из супервизора и установите для свойства view
контроллера значение nil
, метод viewDidUnload
будет вызываться не. Тонкая точка заключается в том, что даже если представление диспетчера представлений уже выпущено и установлено на нуль к моменту, когда контроллер получает didReceiveMemoryWarning
, так что на самом деле нет никакого вида для выгрузки для контроллера, viewDidUnload
будет вызываться, если вы вызовите реализацию суперкласса didReceiveMemoryWarning
.
Вот почему не рекомендуется вручную устанавливать свойство view
контроллера представления на nil. Если вы это сделаете, вы можете отправить сообщение viewDidUnload
. Я думаю, ваше понимание viewDidUnload
более желательно, но, по-видимому, это не текущее поведение.
- Контроллеры отображения всплывающих окон
Если вы имеете в виду "удаление из супервизора" путем "popping", это уменьшает количество удерживаемых просмотров, но необязательно освобождает его.
Если вы имеете в виду выскочить из UINavigationController, это фактически уменьшит счетчик хранения самого контроллера представления. Если контроллер просмотра не сохраняется другим объектом, он будет освобожден, желательно с его представлением. Как я объяснил, на этот раз вызывается viewDidUnload
not.
Технически, показатель удержания может не снизиться до нуля. Объект, скорее всего, будет просто освобожден без предварительной установки счета в ноль.
Чтобы убедиться, что сам контроллер представления обычно не освобождается по умолчанию из-за предупреждения о памяти.
Ответ 2
didReceiveMemoryWarning
...
Действие. Отпустите все, что вам не нужно, скорее всего, отмените то, что вы могли настроить в viewDidLoad.
Это неправильно. Все, что вы воссоздаете в viewDidLoad
, должно быть выпущено (и установлено в nil
) в viewDidUnload
. Как вы отметили ниже, didReceiveMemoryWarning
также вызывается, когда вид виден. В didReceiveMemoryWarning
вы должны выпускать такие вещи, как кеши или другие контроллеры представлений, на которые вы держитесь, которые могут быть воссозданы лениво в следующий раз, когда они потребуются (т.е. Путем реализации их getter вручную).
viewDidUnload
...
Действие - как правило, любые IBOutlets, которые вы выпускаете в dealloc, также должны быть освобождены (и ссылки установлены на нуль) в этом методе. Обратите внимание, что если свойства будут сохранены, то их установка будет равна нулю.
Правильно. Как правило, все, что вы создаете в viewDidLoad и все IBOutlets, объявленные как retain
, должно быть выпущено и установлено здесь nil
.
dealloc
...
Действие - освободить все объекты, сохраненные классом, включая, но не ограничиваясь, все свойства с сохранением или копированием.
Правильно. Стоит отметить, что это включает все объекты, которые вы обрабатываете в viewDidUnload
, потому что последний неявно не вызван в процессе dealloc
(AFAIK, не совсем уверен). Поэтому важно установить все объекты выпусков на nil
в viewDidUnload
, потому что в противном случае вы рискуете отпустить что-то дважды (сначала в viewDidUnload
, затем снова в dealloc
), если вы установите указатель на nil
, релиз в dealloc
не будет иметь эффекта).
Контроллеры отображения и памяти
Вопрос 2 - Выводит ли вид снимок из памяти?
Не обязательно. Это деталь реализации, о которой вы не должны беспокоиться. Независимо от нынешней практики Apple может изменить ее в следующей версии.
Ответ 3
Просто обновите этот поток, чтобы он соответствовал iOS6:
viewDidUnload и viewWillUnload устарели в iOS6. Эти методы никогда не называются.
Для этого и других устаревших методов см.: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/DeprecationAppendix/AppendixADeprecatedAPI.html
Ответ 4
Форма iOS 6 и далее, как мы можем проверить, загружен ли просмотр снова. Поскольку "viewDidUnload" устарел. Вы уверены, что "loadView" и "viewDidload" вызовут, если представление будет удалено после предупреждения "didReceiveMemoryWarning".