UIViewController предотвращает просмотр с разгрузки
Когда мое приложение iPhone получает предупреждение о том, что просмотры UIViewControllers, которые в настоящее время не видны, выгружаются. В одном конкретном контроллере выгрузка вида и выходов довольно смертельна.
Я ищу способ предотвратить разгрузку этого представления. Я считаю, что это поведение довольно глупое - у меня механизм кэширования, поэтому, когда появляется предупреждение о памяти, я выгружаю тонны данных, и я освобождаю достаточно памяти, но мне определенно нужен этот взгляд нетронутым.
Я вижу, что UIViewController имеет метод unloadViewIfReloadable
, который вызывается при появлении предупреждения о памяти. Кто-нибудь знает, как сказать Cocoa Коснитесь, что мое представление не перезагружается?
Любые другие рекомендации по предотвращению выгрузки моего представления из памяти в память?
Заранее спасибо
В документах Apple о жизненном цикле просмотра контроллера просмотра говорится:
didReceiveMemoryWarning - По умолчанию реализация высвобождает только представление если он определяет, что это безопасно делать так
Теперь... Я переопределяю didReceiveMemoryWarning
с пустой функцией, которая просто вызывает NSLog, чтобы сообщить мне, что было получено предупреждение. Однако - просмотр все равно разгружается. Плюс, по какому критерию точно решено, безопасно ли выгрузить разбух... о! так много вопросов!
Ответы
Ответ 1
Что, по-видимому, работает для меня, это переопределить setView:
, чтобы игнорировать параметр в nil. Это kludgy, но тогда, это проблема kludgy, и это сделало трюк:
-(void)setView:(UIView*)view {
if(view != nil || self.okayToUnloadView) {
[super setView:view];
}
}
Ответ 2
В соответствии с документами реализация по умолчанию didReceiveMemoryWarning: освобождает представление, если это безопасно (т.е.: superview == nil),
Чтобы предотвратить публикацию представления, вы можете переопределить didReceiveMemoryWarning: но в вашей реализации не вызывайте [super didReceiveMemoryWarning]
. То, что представление выпущено по умолчанию (если не видно).
По умолчанию didReceiveMemoryWarning освобождает представление, вызывая [viewcontroller setView:nil]
, поэтому вместо этого вы можете переопределить его.
Ответ 3
Неужели это так просто?
Несмотря на то, что нигде в документации это не упоминается, кажется, что если я исключительно сохраняю свой вид в viewDidLoad, он не будет выпущен в Memory Warning. Я пробовал с несколькими последовательными предупреждениями в симуляторе, и все они кажутся хорошими.
Итак... трюк на данный момент - "сохранить" в viewDidLoad и релиз в dealloc - таким образом, viewcontroller "застревает" с представлением до момента его освобождения.
Я проведу еще немного и напишу о результатах
Ответ 4
Я не думаю, что любая из этих идей работает. Я попытался переопределить [didReceiveMemoryWarning], и это сработало для некоторых телефонов, но обнаружил, что один телефон выгрузил представление ПЕРЕД тем, что этот метод был даже вызван (должен был быть в крайне низкой памяти или что-то в этом роде). Переопределение [setView] создает множество предупреждений о регистрации журналов, поэтому я не буду рисковать Apple. Сохранение вида просто приведет к утечке этого вида - это предотвратит сбои, но не работает - представление будет заменено в следующий раз при загрузке пользовательского интерфейса контроллера.
Итак, вы просто должны планировать, что ваши взгляды разгружаются в любое время, когда они за пределами экрана, что не идеально, но вы идете. Лучшие образцы, которые я нашел для работы с этим, - это немедленная фиксация, поэтому ваш пользовательский интерфейс всегда обновляется или копирует-редактирует-копирует, где вы копируете свою модель во временный экземпляр, заполняете свои представления и используете немедленную фиксацию с помощью этот экземпляр, затем скопируйте изменения обратно в исходную модель, когда пользователь нажимает "сохранить" или что-то еще.
Ответ 5
Поскольку принятое решение имеет проблемы с тем, что viewDidUnload
все еще вызывается, даже если представление было заблокировано от очистки, я использую другой, хотя все еще хрупкий подход. Система выгружает представление с помощью сообщения unloadViewForced:
для контроллера, поэтому я перехватываю это, чтобы заблокировать сообщение. Это предотвратит путаный вызов viewDidUnload
. Здесь код:
@interface UIViewController (Private)
- (void)unloadViewForced:(BOOL)forced;
@end
- (void)unloadViewForced:(BOOL)forced {
if (!_safeToUnloadView) {
return;
}
[super unloadViewForced:forced];
}
У этого есть очевидные проблемы, поскольку он перехватывает недокументированное сообщение в UIViewController.
progrmr отправил ответ выше, который рекомендует перехватывать didReceiveMemoryWarning
. Основываясь на следах стека, которые я видел, перехватывать это тоже нужно. Я не пробовал этот маршрут, хотя, поскольку я обеспокоен, может быть и другая очистка памяти, которая также была бы заблокирована (например, заставить ее не вызывать дочерние контроллеры представления с предупреждающим сообщением).