UIImage imageNamed требует pathForResource?
Насколько необходимо искать путь к изображению с помощью метода NSBundle
pathForResource
при создании UIImage
с помощью imageNamed
? Я вижу коды учебников, которые просто определяют имя изображения напрямую, а затем код, который проходит лишнюю милю, чтобы сначала найти путь.
По моему опыту, я всегда просто использовал имя напрямую, и он всегда работал нормально. Я предположил, что он автоматически знал, как найти изображение. Насколько важно или при каких обстоятельствах было бы необходимо сделать больше, чем это?
Ответы
Ответ 1
Документы говорят, что "метод ищет изображение с указанным именем в главном пакете приложений", поэтому Id говорит, что вы всегда можете использовать только имя. Единственным исключением могут быть изображения, хранящиеся внутри подпапок, особенно если у вас есть foo/image.png
и bar/image.png
. Я не знаю, будет ли работать [UIImage imageNamed:@"foo/image"]
, но его тривиально попробовать.
(В этих случаях немного сбивает с толку то, что группы в дереве Xcode не соответствуют папкам в результирующем пакете приложений. Их содержимое разбивается на корень пакета, если вместо этого вы не используете ссылку на синюю папку регулярной группы.)
Ответ 2
Не совсем... это ответ на исходный вопрос:
Насколько необходимо искать путь к изображению с помощью метода NSBundle pathForResource при создании UIImage с использованием imageNamed?
Не намного. Насколько правильно принят принятый ответ от Zoul и другой из Ranga. Справедливости ради: они правильны, если вы говорите о структуре каталогов пакетов приложений или для (редкого) случая, когда изображение находится в "голубой" папке в Xcode (подробнее об этом позже), но не для большинства общие случаи
В любом случае, к одному истинному ответу.
Как обычно, я нашел этот вопрос, пытаясь найти ответ сам. Я никогда не нашел документацию или другие ответы на этот вопрос удовлетворительными, поэтому я решил проверить.
Мои данные теста все ниже, но позвольте мне обобщить результаты здесь.
Короче говоря, при использовании imageNamed: для загрузки изображений это зависит от того, где вы их помещаете:
-
если ваши изображения находятся в корне вашего проекта, даже если они организованы в чисто логической группе Xcode, тогда нет, вы не
нужно подумать о пути: просто имя изображения.
-
если ваши изображения находятся в группе, прикрепленной к каталогу в вашей файловой системе, через "создавать группы для добавления папок", вам все равно не нужно беспокоиться о имени.
-
если ваши изображения находятся в "голубой" группе, прикрепленной к каталогу в вашей файловой системе через "создавать ссылки на папки для добавленных папок", вы можете загрузить его с помощью imageNamed: указав относительный путь как было предложено (по совпадению?) принятым ответом выше.
-
если вы используете основную альтернативу imageNamed:, imageWithContentsOfFile: вам действительно нужен полный путь к файлу, включая путь пакета, что означает, что вам нужно знать, как структура навигатора Xcode переводится в пути в вашем структура каталога пакетов.
Другие важные различия между этими двумя методами:
- imageNamed не требует, чтобы вы указали расширение типа файла,
поэтому просто "значок" не "icon.png", тогда как imageWithContentsOfFile делает
требуется полное имя файла
- эта первая точка помогает со второй функцией: imageNamed будет
автоматически загружать версию сетчатки изображения, если она есть, добавив @2x к имени вашего файла. Поэтому, если вы попросите "значок", на
Retina Display, он попытается загрузить "[email protected]".
imageWithContentsOfFile не
- imageNamed кэширует изображение: в нем много
споры вокруг него: если вы ищете SO или Интернет в целом, вы будете
найти много сообщений, рекомендующих вам избежать этого, потому что это не
правильно очистите его. Это, однако, было исправлено несколько лет назад, поэтому вы
не нужно беспокоиться о том, что он не очистил свой кеш. Вы все еще
нужно беспокоиться о том, что он вообще кэширует. Если ваш
изображения большие и не загружаются очень часто, вы сохраните
память, загружая их из файла, а не кэшируя их. Это
не имеет ничего общего с утечками: даже если у вас нет утечек, вы все равно
имеют ограниченную память на устройстве, и вы не хотите кэшировать
без необходимости. Это классический компромисс кэширования: что еще
важно в вашей ситуации? Производительность памяти или производительность процессора
(Время).
Итак, мои тесты.
Я создал простое приложение UITableView с тремя простыми файлами значков, показанными в строках таблицы, используя разные методы. Значки различаются по своему расположению в структуре проекта Xcode. Обратите внимание на акцент на Xcode. Ключом к пониманию ответа на исходный вопрос является то, что в приложении iOS есть три совершенно разные структуры каталогов проекта: там вы видите в навигаторе Xcode, тот, что в файловой системе для того же проекта, который вы видите в Finder (щелкните правой кнопкой мыши любой элемент в навигаторе Xcode и выберите "показать в Finder" ) и, как вы редко видите, структуру каталогов "bundle" развернутого приложения. Вы также можете увидеть эту последнюю в Finder - найдя свое приложение в ~/Library/Application Support/iPhone Simulator и свернув в каталог .app. Я покажу вам свою фотографию через минуту.
Итак, в моем приложении я перетащил все три файла изображений png в Xcode по-разному:
-
icon1.png(часы), я перетащил его как файл в корень проекта Xcode,
затем я позже создал новую группу в Xcode и перетащил ее в
что. Эта группа не представлена никаким каталогом в файле
system: это чистая группа Xcode. Следовательно, это имя: "JustGroup"
-
icon2.png(глаз), я изначально поставил свою файловую систему в каталог, называемый
"RealDir", и я перетащил весь этот каталог в Xcode, и когда
спросил, я выбрал вариант "Создать группы для любых добавленных папок".
Это означает, что группа RealDir в Xcode привязана к реальному
каталог под названием RealDir в файловой системе (в моем каталоге проектов)
и там находится значок2.png.
-
icon3.png(цель), я также имел в отдельном каталоге, который я также перетаскивал
в Xcode. Только на этот раз я выбрал второй вариант радио "Создать
ссылки на папки для любых добавленных папок ". Это создает так называемый" синяя" группа в Xcode. Подробнее о том, что это все о позже. я
называется эта группа (и каталог) "FolderReference"
Вот выбор из того, что Xcode дает вам:
![Xcode's dialog when dragging a directory in]()
И вот как выглядит моя структура проекта в Xcode:
![Xcode navigator project structure]()
Теперь, в моем приложении, я использовал два метода для загрузки каждого из значков: UIImage imageNamed: и UIImage imageWithContentsOfFile. Я создал ряд строк в моей таблице, причем заголовок каждой ячейки является именем группы, содержащей значок: JustGroup, RealDir или FolderReference, плюс имя используемого метода: imageNamed vs fromFile (который я использую как аббревиатура imageWithContentsOfFile)
Метка ярлыка ячейки (более слабый текст под заголовком) показывает имя файла или пути, которые я дал методу.
Чтобы быть ясным, в случае с "fromFile" я добавляю путь пакета к "относительному" имени, которое вы видите.
Поэтому для "fromFile" я действительно использую этот код:
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *imagePath = [NSString stringWithFormat:@"%@/%@", bundlePath, filePath];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
где "filePath" - это путь, который вы видите на ярлыке ячейки таблицы.
Для imageNamed:, с другой стороны, filePath в элементе ячейки передается дословно.
И образ строки - это, естественно, загруженное изображение. Поэтому для строк в таблице, у которых нет изображения, загрузка изображения не удалась.
Здесь, в двух словах, есть результаты. Если вы ничего не читаете об этом посту, по крайней мере взгляд на это изображение скажет вам все, что вам нужно знать.
![app shows which icons were loaded]()
Здесь основное объяснение в легко усваиваемых точках:
-
как указано в официальной документации, метод imageNamed: загружает изображения из набора приложений. Это означает, что вам не нужно указывать местоположение пакета, только имя файла. И даже тогда просто базовое имя файла. Документация здесь немного тонкая, поэтому должно быть ясно, что она загружает изображение из заданного пути файла относительно корневого каталога приложения.
-
(здесь, обратите внимание на кикер, это правило) о том, что правило о каталоге пакетов, ссылается на корневой каталог в вашем комплекте вашего развернутого приложения. Если вы исследуете, это означает, что в самом каталоге ".app". Это не то же самое, что корневой каталог проекта Xcode в навигаторе Xcode, и он не совпадает с корневым каталогом проекта Xcode в finder
-
это связано с тем, что при развертывании вашего приложения на устройстве (или симуляторе) все каталоги проектов, представленные "группами для добавленных папок", сглаживаются. То есть каталог игнорируется, и все его содержимое бесцеремонно выгружается в корневой каталог пакета. (Я говорю "бесцеремонно", потому что, если в разных папках есть файлы с одинаковым именем, они будут сталкиваться здесь, и вы не получите никакой помощи в разрешении возникающих проблем.) Это пример RealDir в моем примере: in развернутое приложение, RealDir больше не существует, и icon2.png остается смешаться с общей популяцией (страшно). Это почти не говорит о том, что "JustGroup", чисто логическая группа Xcode, также игнорируется - в любом случае она никогда не была настоящим каталогом, просто визуальная помощь пользователю Xcode, а icon1.png также входит в корень пакета.
-
Вот почему imageNamed: удалось загрузить значок2.
-
Кроме того, почему imageWithContentsOfFile не удалось найти его в "RealDir/image2.png": поскольку в развернутом приложении нет каталога RealDir.
-
"голубые папки", с другой стороны, то есть каталоги, представленные "ссылками на папки для добавленных папок", фактически сохраняются в структуре каталогов приложений. Это, по-видимому, точка синих папок: они дают вам способ создать структуру каталогов в развернутом приложении. Я не уверен в оригинальном raison d'etre для этого, но один хороший пример использования - это то, где у вас есть несколько каталогов, содержащих альтернативные версии файлов ресурсов с тем же именем, и вы хотите, чтобы ваше приложение могло переключаться между ними во время выполнения путем изменения каталога. Во всяком случае, icon3.png в моем FolderReference, остался в моем каталоге FolderReference в развернутом приложении.
- Вот почему imageNamed: не удалось найти его с помощью значка "icon3", но можно найти его с помощью "FolderReference/icon3"
- imageWithContentsOfFile смог найти его также с помощью FolderReference, но только при подключении не забудьте указать полный путь пакета, используя приведенный выше код. (Основное отличие здесь: imageNamed работает с относительным путем в этом случае, imageWithContentsOfFile всегда работает с абсолютным путем).
Чтобы уточнить, вот мои структуры папок:
Вы видели мою навигационную структуру проекта Xcode выше, вот каталог файловой системы под ней:
![Finder Xcode project directory structure]()
И, наконец, возможно, самое главное, структура каталогов файловой системы с развернутой структурой:
![deployed bundle directory structure]()
Примечание. Я нашел это в этом месте на моем Mac: вы найдете свое место в аналогичном месте - вам, возможно, придется немного поискать, чтобы найти подкаталог с уродливым GUID-именем, содержащий ваше приложение.
~/Library/Application Support/iPhone Simulator/5.1/Applications/4EB386B2-CD7E-4590-9757-18DDDEE6AF4F/ImageLoadingTest.app
Надеюсь, это поможет. Тестирование, изучение и, наконец, его описание, безусловно, помогли мне.
Ответ 3
Я создал новый проект Xcode (один вид, AppDelelgate, класс ViewController, раскадровку и т.д.).
Создана группа изображений.
Использовал Paintbrush, чтобы создать файл PN1.xng 16x16 и упал его в группу "Изображения" в Xcode (пусть Xcode скопирует файлы).
В ViewController viewDidLoad добавлен код:
UIImageView* imageView=[[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 16, 16)];
UIImage *image = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"Images/Wall1" ofType:@"png"]];
imageView.image = image;
UIImageView* imageView=[[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 16, 16)];
UIImage *image = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"Wall1" ofType:@"png"]];
imageView.image = image;
[self.view addSubview:imageView];
Измените приложение на моем телефоне, изображение не появится
Добавлена точка останова в [self.view addSubview: imageView];
Изображение было null
Открыл терминал и изменил каталог в моем проекте, Wall1.png не был папкой группы "Изображения" . Удалил png из проекта, создал папку "Изображения" , переместил Wall1.png в папку. Добавлен существующий файл Wall1.png в группу Images.
Запустите приложение, изображение все еще не отображается.
Изображение было null
Измененные изображения /Wall 1 to Wall1
Запустите приложение, появится изображение стрелы1
Если вы создаете группу для своих изображений, Xcode не создает соответствующий каталог. Создайте его вручную, если хотите (я предпочитаю, чтобы мои изображения были в отдельной папке). Не указывайте полный путь к файлу изображения при использовании UIImage imageWithContentsOfFile.
Ответ 4
Попробуйте это.
[UIImage imageNamed:@"your directory path of image"]
[UIImage imageNamed: @ "Dir1/folder1/folder2/imagename.jpeg" ]