Разница между [UIImage imageNamed ...] и [UIImage imageWithData ...]? - PullRequest
65 голосов
/ 25 ноября 2008

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

[UIImage imageNamed:fullFileName]

или

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

[UIImage imageWithData:imageData];

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

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

Ответы [ 8 ]

91 голосов
/ 25 ноября 2008

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

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

10 голосов
/ 19 августа 2013

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

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

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

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

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

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

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


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

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

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

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

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

10 голосов
/ 25 ноября 2008

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

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

7 голосов
/ 22 августа 2011

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

NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
UIImage* yourImage = [[[UIImage alloc] initWithContentsOfFile:imagePath] autorelease];
5 голосов
/ 25 ноября 2008

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

3 голосов
/ 25 ноября 2008

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

0 голосов
/ 17 декабря 2010

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

0 голосов
/ 25 ноября 2010

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

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