Разница между [UIImage imageNamed...] и [UIImage imageWithData...]?

Я хочу загрузить некоторые изображения в свое приложение из файловой системы. Там 2 простых способа сделать это:

[UIImage imageNamed:fullFileName]

или

NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
NSData *imageData = [NSData dataWithContentsOfFile:fileLocation];

[UIImage imageWithData:imageData];

Я предпочитаю первый, потому что это намного меньше кода, но я видел, как некоторые люди говорили, что изображение кэшировано и что этот метод использует больше памяти? Поскольку я не доверяю людям на большинстве других форумов, я думал, что задаю здесь вопрос, есть ли какая-то практическая разница, и если да, то какой из них "лучше"?

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

Ответ 1

Это зависит от того, что вы делаете с изображением. Метод imageNamed: кэширует изображение, но во многих случаях это помогает использовать память. Например, если вы загружаете изображение 10 раз для отображения вместе с некоторым текстом в виде таблицы, UIImage будет хранить только одно представление этого изображения в памяти вместо выделения 10 отдельных объектов. С другой стороны, если у вас очень большое изображение, и вы не используете его повторно, вы можете загрузить изображение из объекта данных, чтобы убедиться, что оно удалено из памяти, когда вы закончите.

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

Ответ 2

По моему опыту [UIImage imageNamed:] имеет значительно лучшую производительность, особенно при использовании в UITableViews.

Это не только память, но и декодирование image. С его кэшированием происходит намного быстрее.

Ответ 3

В качестве ссылки API UIImage говорится:

+ (UIImage *) imageNamed: (NSString *) name

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

+ (UIImage *) imageWithContentsOfFile: (NSString *) путь

Этот метод не кэширует объект изображения.

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

И, с другой стороны, в приложении будет некоторый элемент UI, который будет присутствовать во время жизненного цикла приложения, например, кнопка, вид логотипа, поэтому эти изображения, используемые эти элементы ui могут также присутствовать в течение жизненного цикла приложения, вы не будете учитывать, должно ли это изображение быть кешем или нет. Поэтому вы можете использовать метод imageNamed.


Напротив, в приложении часто есть несколько элементов пользовательского интерфейса, которые создаются динамически. Например, наше приложение поддерживает динамический фон, так что пользователь может выбрать фон, который им нравится. И фон может быть изображением. Поэтому у нас может быть интерфейс, в котором перечислены партии из другого фона (часто показываются с помощью UIImageView) для выбора пользователем, мы можем назвать представление списка MyBackgroundListView. Так как пользователь выбирает background image, MyBackgroundListView должен быть уничтожен, так как он завершил свою работу. В следующий раз, когда пользователь захочет изменить свой фон, мы можем создать MyBackgroundListView. Так что изображения, используемые MyBackgroundListView, не должны кэшироваться, или наша память приложения закончится. Поэтому на этот раз вы должны использовать imageWithContentsOfFile.

Как Apple doc Поддержка экранов с высоким разрешением в представлениях говорит

На устройствах с экранами с высоким разрешением методы imageNamed:, imageWithContentsOfFile: и initWithContentsOfFile: автоматически ищут версию запрошенное изображение с модификатором @2x в его имени. Если он найдет один, он загрузит это изображение. Если вы не предоставляете версию изображения с высоким разрешением, объект изображения по-прежнему загружает изображение стандартного разрешения (если оно существует) и масштабирует его во время рисования.

чтобы вы беспокоились о пути поиска изображения для проблемы сетчатки сетчатки. IOS поможет вам справиться с этим.

Извините за моего бедного английского. Может быть полезно.

Ответ 4

Если вы не хотите, чтобы ваше изображение было кэшировано, вы также можете напрямую использовать initWithContentsOfFile:

NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
UIImage* yourImage = [[[UIImage alloc] initWithContentsOfFile:imagePath] autorelease];

Ответ 5

Мне также сказали, что [UIImage imageNamed:] делает слишком много кеширования, а изображения не часто выпускаются. Мне сказали быть осторожным, чтобы использовать его.

Ответ 6

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

Ответ 7

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

Ответ 8

Я не верю, что изображение вообще кэшируется, и я не знаю, почему вы все это говорите. UIImage является подклассом NSObject, который использует контрольные счетчики для отслеживания того, с чем он связан. Поэтому, когда вы загружаете изображение, он делает то же самое. Если вы загружаете одно и то же изображение несколько раз, он будет (или должен) иметь только одну копию изображения в памяти и просто увеличивать счетчик ссылок каждый раз, когда вам нужно что-то использовать с этим изображением. Посредством ссылочных счетчиков я имею в виду, что когда счетчик достигает 0, он удаляет себя. поэтому "alloc", "сохранить" составляют +1 к счету, а "release" - -1. Это не только лучший способ управления памятью, но и этот стиль программирования также помогает очищать утечки памяти.