Проблемы утечки памяти в UIViewController - PullRequest
9 голосов
/ 04 марта 2009

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

Ситуация, с которой я имею дело, включает в себя 2 экземпляра класса UIViewController. При запуске создается первый экземпляр, и его представление добавляется в другой «главный» класс UIViewController, который является частью MainWindow.xib. На этом первом экземпляре есть кнопка «информация», которая при нажатии переключается на новый экземпляр класса UIViewController (если он еще не был создан). «Основной» UIViewController управляет этим переключением с помощью обычной анимации. Основные настройки можно увидеть в книге Дейва Марка «Начало разработки iPhone: изучение iPhone SDK».

Проблема, которая возникает, заключается в том, что после первого нажатия кнопки «информация» память выделяется для нового второго экземпляра UIViewController и не освобождается до тех пор, пока приложение не завершится. Из-за количества элементов в этом информационном представлении он использует приблизительно 1 МБ памяти после создания экземпляра, и его представление добавляется в суперпредставление. Любые попытки последовательно уничтожить и воссоздать этот экземпляр приводят к утечке памяти, аналогичной той, которая существует, если вы пытаетесь сделать то же самое с экземплярами класса UIImagePickerController. Я подозреваю, что первопричина между двумя классами одинакова.

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

Класс UIImagePickerController временно использует почти 15-18 МБ, в то время как он обрабатывает 2-мегапиксельное изображение перед освобождением своих внутренних ссылок и вызывается делегат "imagePickerController: didFinishPickingImage". Я сталкиваюсь с предупреждениями о нехватке памяти, как только второй экземпляр UIViewController был создан с помощью кнопки «Информация», а затем пользователь решает сделать еще одну фотографию.

Технически память не протекает независимо от того, выполняете ли вы снимки снова и снова с помощью или без нажатия кнопки «Информация» в моем случае, но из-за других проблем, связанных с фоновыми процессами на iPhone (Safari и т. Д.), Которые вы не можете контролировать, вы ДОЛЖНЫ освободить как можно больше памяти при работе с такими вещами, как камера.

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

Ответы [ 4 ]

4 голосов
/ 09 марта 2009

Вы загружаете второй контроллер вида из NIB? Если это так, вы захотите проверить, правильно ли вы освобождаете связанную память.

Вот как выглядит типичный контроллер представления на основе NIB в моих проектах.

SomeViewController.h

@interface SomeViewController : UIViewController {
    UILabel *someLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *someLabel;

@end

SomeViewController.m

@implementation SomeViewController

@synthesize someLabel;

- (void)dealloc {
    // Release our retained IBOutlets
    self.someLabel = nil;
    [super dealloc];
}

@end
1 голос
/ 05 марта 2009

Есть ли у вас какие-либо циклы в вашей цепочке собственности? Что-то вроде:

@interface FirstViewController: UIViewController {
  SecondViewController *secondViewController;
}
@end

@interface SecondViewController: UIViewController {
  FirstViewController *firstViewController;
}
@end

Если вы не прервете этот цикл явным образом при сбросе этих контроллеров представления, они утекут.

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

1 голос
/ 05 марта 2009

Один из способов уменьшить использование памяти - изменить размер изображения до любого необходимого размера (если, конечно, вам не нужно изображение размером 320x480). Это очень помогло в моем случае.

Меняется ли второй viewcontroller, о котором вы говорите? Если нет, то было бы лучше сделать его синглтоном и использовать тот же экземпляр. Вы можете в любое время изменить значения, используемые viewcontroller. В этой статье объясняется, как можно создавать одноэлементные объекты (с кодом)

В другой статье здесь показано использование одноэлементного класса (хотя оно отличается от вашего варианта использования, оно пояснит, как использовать синглтоны)

Я бы также предложил создать одноэлементный объект для UIImagePickerController.

0 голосов
/ 24 октября 2009

Возможно, вы могли бы сохранить изображение перед переходом в информационное представление. После сохранения отпустите изображение и затем перейдите в информационный вид. Если пользователь возвращается, загрузите изображение из папки.

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