Как реализовать didReceiveMemoryWarning? - PullRequest
47 голосов
/ 12 марта 2010

Я разработал простое приложение для iPhone с поддержкой определения местоположения, которое функционально работает очень хорошо в соответствии с нашими ожиданиями, за исключением низкого уровня памяти телефона.

В нехватке памяти телефона мое приложение просто падает, и если я увеличиваю память телефона, освобождая место, оно снова начинает работать без сбоев.

когда я занялся поиском этой проблемы, обнаружил, что в условиях нехватки памяти ОС будет отправлять didReceiveMemoryWarning всем контроллерам в текущей иерархии, чтобы каждый из них реализовывал метод didReceiveMemoryWarning, а также устанавливал для iboutlet значение nil для вид, который в данный момент не виден.

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

Итак, со всеми этими средствами лучше всего справиться с состоянием памяти низкого уровня, созданным Iphone, путем реализации методов didReceiveMemoryWarning и viewDidUnload .

Пожалуйста, приведите пример или ссылку, если возможно, для решения вышеуказанной проблемы.

спасибо.

Ответы [ 6 ]

21 голосов
/ 24 марта 2010

Один пример, который я публикую ... который я скопировал откуда-то ... это может дать вам некоторое представление ...

- (void)didReceiveMemoryWarning {

    // Release anything that's not essential, such as cached data (meaning
    // instance variables, and what else...?)

    // Obviously can't access local variables such as defined in method
    // loadView, so can't release them here We can set some instance variables
    // as nil, rather than call the release method on them, if we have defined
    // setters that retain nil and release their old values (such as through use
    // of @synthesize). This can be a better approach than using the release
    // method, because this prevents a variable from pointing to random remnant
    // data.  Note in contrast, that setting a variable directly (using "=" and
    // not using the setter), would result in a memory leak.
    self.myStringB = nil;
    self.myStringD = nil;
    [myStringA release];// No setter defined - must release it this way
    [myStringC release];// No setter defined - must release it this way

    /* 3. MUST CONFIRM: NOT necessary to release outlets here - See override of
       setView instead.
    self.labelA = nil;
    self.imageViewA = nil;
    self.subViewA = nil;
     */
    // Releases the view if it doesn't have a superview
    [super didReceiveMemoryWarning];
}
15 голосов
/ 08 апреля 2013

В iOS 5 и более ранних версиях.

Когда контроллер получает предупреждение о памяти, будет вызвано didReceiveMemoryWarning. В то время, если представление контроллера не находится в иерархии представлений, представление будет установлено равным nil, и viewDidUnload будет автоматически вызываться. Таким образом, вещи, которые мы должны сделать в viewDidUnload, - освободить вложенное представление, созданное в viewDidLoad или созданное из Nib. Как это:

- (void)viewDidUnload
{
    self.subView = nil;
    self.subViewFromNib = nil;
}

- (void)didReceiveMemoryWarning
{
    self.someDataCanBeRecreatedEasily = nil;
    [super didReceiveMemoryWarning];
}

На iOS6.

Контроллер не автоматически отключает вид при получении предупреждения о памяти. Поэтому viewDidUnload никогда не вызывается. Но мы все еще должны освободить наше представление (включая вспомогательное представление), когда происходит предупреждение памяти. Вот так.

- (void)didReceiveMemoryWarning
{
    if ([self isViewLoaded] && [self.view window] == nil) {
        self.view = nil;
        self.subView = nil;
        self.subViewFromNib = nil;
    }
    self.someDataCanBeRecreatedEasily = nil;
    [super didReceiveMemoryWarning];
}

Обратите внимание, что мы не вызываем [self view], пока не узнаем, что представление загружено. причина, что этот метод автоматически загрузит представление, если представление не загружено.

Обратите внимание, что мы можем освободить представление только тогда, когда оно не добавлено в окно.

15 голосов
/ 31 марта 2010

Память предупреждает вас о том, что вы должны распоряжаться любыми ресурсами, которые не являются абсолютно критическими. Большинство ваших контроллеров будут зависать от кэшей данных, промежуточных данных или других фрагментов, часто для сохранения пересчета. Когда они получают предупреждения памяти, они должны начать сбрасывать все, что им не нужно немедленно для работы.

То, как вы определяете, что является «критическим», полностью зависит от дизайна вашего приложения. Например, игра OpenGL может определить, что в данный момент на экране имеются ценные текстуры, и скрыть текстуры, которые не видны, или данные уровня, находящиеся за пределами текущей игровой области. Приложение с обширными журналами сеансов (например, клиент IRC) может выгружать их из памяти на диск.

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

5 голосов
/ 12 марта 2010

Вам решать, что делать в didReceiveMemoryWarning. ОС сообщает вам, что памяти мало, и вам нужно как можно быстрее освободить как можно больше. Идея состоит в том, чтобы освободить все кэшированные данные, выгрузить невидимые представления и т. Д. Подробности зависят от приложения.

4 голосов
/ 26 марта 2010

Вы также можете высвободить память в didReceiveMemoryWarning, которую вы выделили для статических переменных в ваших классах. Поскольку после выделения памяти для статических переменных она не будет освобождена во время выполнения приложения.

2 голосов
/ 30 марта 2010

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

Некоторые образцы (например, TableViewSuite) даже делают что-то еще; -)

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