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

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

[UIImage imageNamed:fullFileName]

или же:

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

[UIImage imageWithData:imageData];

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

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

8 ответов

Решение

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

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

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

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

Как говорит API-интерфейс UIImage:

+ (UIImage *) imageNamed: (NSString *) имя

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

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

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

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

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


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

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

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

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

Извините за мой плохой английский. Пусть это будет полезно.

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

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

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

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

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

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

Другие вопросы по тегам