2009-04-30 2 views
4

Я читал, что imageNamed: плохо при попытке инициализировать изображения. Но тогда лучший способ? Я использую imageWithContentsOfFile и, проходя путь изображения в моей папке ресурсовiPhone - Самый эффективный способ памяти для инициализации изображения?

[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:@"jpg"] 

Этот вызов производится около 30 раз в цикле.

Теперь, когда я запускаю свое приложение с помощью инструментов, я вижу, что NSString использует большую память для операций, подобных описанным выше, где мы используем строковые литералы (@ "jpg"). Приборы показывают ответственного абонента как [ NSBundle mainBundle], и ​​это, в свою очередь, указывает на строку, когда я использую строковый литерал для типа.

Итак, каков наиболее эффективный способ инициализации изображений без использования слишком большой памяти?

Я изменил заявление

img = [UIImage imageWithContentsOfFile:[bndl pathForResource:fileName ofType:extn]] 

где extn статична и инициализируется @"jpg". fileName постоянно меняется для каждой итерации цикла for. Но даже тогда максимальное использование NSString связано с [NSBundle mainBundle] и [NSBundle pathForResource:OfType:] согласно приборам.

ответ

5

Я бы не использовал автореализованные объекты, где вы можете внутри цикла. Если инструменты сообщают о множестве обращений к пути NSBundle pathForResource: ofType: call, я бы вытащил часть этой обработки за пределы цикла.

Моей Рекомендованная реализация будет выглядеть примерно так:

NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] retain]; 

for (int i = 0; i < 1000; ++i) 
{ 
    ... 

    NSString *pathForImageFile = [resourcePath stringByAppendingPathComponent:fileName]; 
    NSData *imageData = [[NSData alloc] initWithContentsOfFile:pathForImageFile]; 

    UIImage *image = [[UIImage alloc] initWithData:imageData]; 
    [imageData release]; 

    ... 

    [image release]; 
} 

[resourcePath release]; 

Вы будете накапливать одну autoreleased строки (pathForImageFile), но это не должно быть так плохо. Вы можете создать и освободить пул автозапуска в цикле, но я бы предложил сделать это не более одного раза каждые 10 или 100 циклов, а не каждый проход. Кроме того, сохранение и освобождение на ресурсеPath может быть излишним, но я положил его там, если вы хотите использовать свой собственный пул авторефератов где-то здесь.

+0

Брэд, у меня есть запрос: вместо распределения NSData и загрузки UIImage из него мы не можем напрямую использовать 'imageWithContentsOfFile' или' initWithContentsOfFile' для загрузки изображения? Какой из этих 3 методов будет быстрее, меньше потребляемой памяти (эффективной)? Ваш комментарий пожалуйста. –

+0

@ rohan-patel - Прошло четыре года с момента ответа, поэтому я не уверен, почему я решил сделать это специально, но '-imageWithContentsOfFile:' будет генерировать объекты с автореализацией. Это одна вещь, которую мы пытались избежать здесь. '-initWithContentsOfFile:' мог бы быть лучшим подходом, но я, возможно, сравнивал это и обнаружил, что он близок к тому времени. Это то, что я сначала проработал. –

+0

Спасибо за ваш комментарий. Если мы думаем в общем контексте (забывая об этом сценарии цикла), что было бы более эффективным? Я думаю, что 'imageWithContentsOfFile:' может быть эффективным. –

1

Что вы можете сделать, чтобы убедиться, что вы выпускаете autoreleased объекты внутри цикла

Перед:

for (int i = 0; i < 1000; ++i) 
{ 
    UImage* img = [UIImage imageWithContentsOfFile: 
     [bndl pathForResource:fileName ofType:extn]]; 
    ... 
} 

После:

for (int i = 0; i < 1000; ++i) 
{ 
    NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; 
    UImage* img = [UIImage imageWithContentsOfFile: 
     [bndl pathForResource:fileName ofType:extn]]; 
    ... 
    [ap release]; 
} 

Но я сомневаюсь, что эти NSString экземпляры могли вызывают слишком много проблем:

  1. UIImages должно занимать гораздо больше памяти, чем строки (> = 100x).
  2. Если ваша петля - всего 30 итераций, и вы попадаете в цикл событий, пул авторесурсов будет выпущен, поэтому вы не должны видеть более 30 строк. (Событие без AP в цикле)

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

+0

Спасибо. Я дважды проверял. Инструменты указывают на линию UIImage и показывают распределение объектов для NSString. В строке нет значений NSString, кроме имени изображения и расширения. – lostInTransit

+0

Есть ли способ, я могу убедиться, что я ничего не пропустил? – lostInTransit

+0

Вы проверяете утечки или распределение объектов? – mfazekas

2

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

Если вы не хотите использовать imageNamed:, первый фрагмент кода в порядке.Если вы беспокоитесь о временных строках, созданных в цикле, поставить это перед циклом:

NSAutoreleasePool * pool = [NSAutoreleasePool new]; 

И это после того, как:

[pool release]; 

Это будет гарантировать, что любые временные объекты внутри цикла высвобождается как только петля выйдет. Однако убедитесь, что все временные объекты, которые вы хотите сохранить , сохраняют. (Например, сами изображения должны быть добавлены в структуру данных, которая их сохранит, например, в виде массива, словаря или набора или сохранена вручную.)

0

Я еще не видел, чтобы кто-нибудь упоминал об этом, но причина, по которой вы видите несколько экземпляров NSString, создаваемых этой линией, состоит в том, что pathForResource: ofType: необходимо объединить строки вместе, чтобы создать полный путь от различных компонентов (имя каталога, имя файла, расширение).

Я твердо в лагере «Не беспокойся об этом». По сравнению с использованием памяти даже для очень маленького изображения несколько десятков экземпляров NSString - это просто шум. Если ваша петля переходит от 30 изображений к нескольким тысячам или что-то еще, то вы можете захотеть создать NSAutoreleasePool внутри цикла.

Смежные вопросы