UIViewController предотвращает выгрузку вида - PullRequest
16 голосов
/ 03 июня 2010

Когда мое приложение для iPhone получает предупреждение о памяти, представления UIViewControllers, которые в данный момент не видны, выгружаются. В одном конкретном контроллере разгрузка вида и розетки довольно фатальная.

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

Я вижу, что в UIViewController есть метод unloadViewIfReloadable, который вызывается при появлении предупреждения о памяти. Кто-нибудь знает, как сказать Cocoa Touch, что мой взгляд не перезагружается?

Есть еще какие-нибудь предложения, как предотвратить выгрузку моего вида из памяти?

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


В документации Apple о жизненном цикле представления контроллера представления указано:

didReceiveMemoryWarning - значение по умолчанию реализация выпускает только представление если он определит, что это безопасно так

Теперь ... я переопределяю didReceiveMemoryWarning пустой функцией, которая просто вызывает NSLog, чтобы сообщить мне, что получено предупреждение. Однако - вид все равно выгружается. Кроме того, по каким критериям точно решено, безопасно ли разгрузить вид ... о! так много вопросов!

Ответы [ 5 ]

15 голосов
/ 03 июня 2010

Согласно документам, реализация по умолчанию didReceiveMemoryWarning: освобождает представление, если это безопасно (т.е.: superview == nil).

Чтобы предотвратить выпуск представления, вы можете переопределить didReceiveMemoryWarning: но в вашей реализации не вызывайте [super didReceiveMemoryWarning]. Вот где представление освобождается по умолчанию (если не видно).

По умолчанию didReceiveMemoryWarning освобождает представление, вызывая [viewcontroller setView:nil], так что вы можете вместо этого переопределить.

13 голосов
/ 24 февраля 2011

Что-то, что, кажется, работает для меня, было переопределить setView:, чтобы игнорировать установку на ноль. Это клёво, но тогда это клёвый вопрос, и он сделал свое дело:

-(void)setView:(UIView*)view {
    if(view != nil || self.okayToUnloadView) {
        [super setView:view];
    }
}
1 голос
/ 03 января 2012

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

@interface UIViewController (Private)
- (void)unloadViewForced:(BOOL)forced;
@end

- (void)unloadViewForced:(BOOL)forced {
    if (!_safeToUnloadView) {
        return;
    }
    [super unloadViewForced:forced];
}

У этого есть очевидные проблемы, так как он перехватывает недокументированное сообщение в UIViewController.

progrmr опубликовал ответ выше, который рекомендует перехватывать didReceiveMemoryWarning вместо этого.Основываясь на следах стека, которые я видел, перехват, который также должен работать.Я не пробовал этот маршрут, хотя, поскольку я обеспокоен, может быть другая очистка памяти, которая также будет заблокирована (например, не вызовет дочерние контроллеры представления с предупреждающим сообщением памяти).

1 голос
/ 17 июня 2011

Я не думаю, что любая из этих идей работает. Я попытался переопределить [didReceiveMemoryWarning], и это сработало для некоторых телефонов, но обнаружил, что один телефон выгружал представление ДО того, как этот метод даже был вызван (должно быть, он был в очень малой памяти или что-то в этом роде). Переопределение [setView] приводит к большому количеству предупреждений журнала, поэтому я бы не стал рисковать этим со стороны Apple. Сохранение представления просто утечет это представление - оно предотвратит сбои, но не будет работать на самом деле - представление будет заменено при следующей загрузке пользовательского интерфейса контроллера.

Так что, на самом деле, вы просто должны планировать, что ваши представления будут выгружены в любое время, когда они находятся за кадром, что не идеально, но вы идете. Лучшие шаблоны, которые я нашел для работы с этим, - это немедленная фиксация, поэтому ваш пользовательский интерфейс всегда актуален, или copy-edit-copy, где вы копируете модель во временный экземпляр, заполняете ваши представления и используете немедленную фиксацию с этот экземпляр, а затем скопируйте изменения обратно в исходную модель, когда пользователь нажмет «сохранить» или что-то еще.

1 голос
/ 03 июня 2010

Может ли это быть так просто?

Несмотря на то, что нигде в документации это не упоминается, кажется, что если я сохраню свое представление исключительно в viewDidLoad, то оно не будет выпущено в Memory Warning. Я попытался с несколькими последовательными предупреждениями в симуляторе, и все все еще кажется хорошим.

Итак ... хитрость на данный момент заключается в том, чтобы «сохранить» в viewDidLoad и выпуске в dealloc - так контроллер представления «застрял» с представлением до момента, когда он должен быть освобожден.

Я еще протестирую и напишу о результатах

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...