根本没有 ...是原始问题的答案:
在使用 imageNamed 创建 UIImage 时,使用 NSBundle 方法 pathForResource 搜索图像路径的必要性有多大?
不多 .. 来自 Zoul 和来自 Ranga 的另一个接受的答案是如何正确。公平地说:如果您谈论的是应用程序包目录结构,或者图像位于 Xcode 中的“蓝色”文件夹中的(罕见)情况(稍后会详细介绍),它们是正确的,但不是大多数常见情况
无论如何,找到一个真正的答案。
像往常一样,我在尝试自己寻找答案时发现了这个问题。我从未找到令人满意的文档或此问题的其他答案,因此我决定进行测试。
我的测试细节都在下面,但让我在这里总结一下结果。
简而言之,当使用 imageNamed: 加载图像时,这取决于您将它们放在哪里:
如果您的图像位于项目的根目录中,即使组织在一个纯逻辑 Xcode 组中,那么不,您不需要
需要考虑路径:只是图像名称。
如果您的图像位于附加到文件系统目录的组中,通过“为添加的文件夹创建组”,那么您仍然不需要担心名字。
如果您的图像位于“蓝色”组中,该组通过“为添加的文件夹创建文件夹引用”附加到文件系统中的目录,那么您可以使用 imageNamed: 通过指定相对路径来加载它正如上面接受的答案所建议的(巧合?)。
如果您使用 imageNamed:、imageWithContentsOfFile: 的主要替代方法,您确实需要包含包路径的文件的完整路径,这意味着您需要知道 Xcode 导航器结构如何转换为捆绑目录结构。
这两种方法的其他重要区别:
- imageNamed 不需要您指定文件类型扩展名,
所以只是“icon”而不是“icon.png”,而 imageWithContentsOfFile 确实
需要完整的文件名
- 第一点有助于实现第二个功能:imageNamed 将
自动通过在文件名中添加@2x 来加载图像的视网膜版本(如果有)。因此,如果您要求“图标”,请在
视网膜显示它会尝试加载“icon@2x.png”。
imageWithContentsOfFile 没有
- imageNamed 缓存图像:其中包含很多
围绕它的争议:如果您搜索 SO 或整个网络,您将
发现很多帖子建议你避免它,因为它没有
正确清除其缓存。然而,这在几年前就已经修复了,所以你
不必担心它无法清除缓存。你仍然做
不过,需要担心它完全缓存的事实。如果你的
图片大并且不经常加载,你会节省
通过从文件加载它们而不是缓存它们来存储内存。这是
与泄漏无关:即使您没有泄漏,您仍然
设备上的内存有限,并且您不想缓存
不必要的。这是经典的缓存权衡:更重要的是
在你的情况下重要吗?内存性能或cpu性能
(时间)。
继续我的测试。
我所做的是创建一个简单的 UITableView 应用程序,其中包含 3 个简单的图标文件,使用不同的方法显示在表格的行中。这些图标在 Xcode 项目结构中的位置不同。请注意对 Xcode 的强调。理解原始问题答案的关键在于,iOS 应用程序中存在三种完全不同的项目目录结构:一种是您在 Xcode 导航器中看到的,另一种是您在 Finder 中看到的同一项目的文件系统(右键单击 Xcode 导航器中的任何项目并选择“在 Finder 中显示”)以及您很少看到的已部署应用程序的“捆绑”目录结构。您也可以在 Finder 中看到最后一个 - 通过在 ~/Library/Application Support/iPhone Simulator 中找到您的应用程序,然后深入到 .app 目录。我马上给你看一张我的照片。
所以在我的应用程序中,我以不同的方式将所有三个图标 png 图像文件拖到 Xcode 中:
icon1.png(一个时钟),我作为文件拖入Xcode项目的根目录,
然后我稍后在 Xcode 中创建了一个新组并将其拖入
那。该组不由文件中的任何目录表示
系统:这是一个纯 Xcode 组。因此它的名字是:“JustGroup”
icon2.png(一只眼睛),我最初将我的文件系统放在名为的目录中
“RealDir”,我把整个目录拖到 Xcode 中,当
问,我选择了“为任何添加的文件夹创建组”选项。
这意味着 Xcode 中的 RealDir 组附加到一个真实的
文件系统中名为 RealDir 的目录(在我的项目目录中)
那个icon2.png就在那里。
icon3.png(一个目标),我也有一个单独的目录,我也拖了
进入 Xcode。只有这一次我选择了第二个单选选项“创建
任何添加的文件夹的文件夹引用”。这将创建一个所谓的
Xcode 中的“蓝色”组。更多关于这一切的内容稍后。一世
将此组(和目录)称为“FolderReference”
这是 Xcode 为您提供的选择的截图:
这是我的项目结构在 Xcode 中的样子:
现在,在我的应用程序中,我使用了两种方法来加载每个图标: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 是逐字传递的。
image 行自然是加载的图像。所以对于表中没有图片的行,图片加载失败。
简而言之,就是结果。如果你没有阅读这篇文章,至少看一眼这张图片就会告诉你你需要知道的一切。
下面是简单易懂的基本解释:
正如官方文档中所述,imageNamed: 方法从应用程序包中加载图像。这意味着您不需要指定捆绑位置,只需指定文件名。即使这样,也只是文件的基本名称。这里的文档有点薄,它应该明确说明它将图像从给定的文件路径 relative 加载到应用程序包根目录。
-
(这是踢球者,注意这一点)关于捆绑目录的规则,指的是您部署的应用程序捆绑包中的根目录。如果你去探索,那意味着在“.app”目录本身。这和Xcode navigator中Xcode项目的根目录不一样,也不和finder中Xcode项目的根目录一样
-
这是因为,在将您的应用部署到设备(或模拟器)时,由“添加文件夹的组”表示的所有项目目录都是扁平化。也就是说,该目录将被忽略,并且其所有内容都会毫不客气地转储到捆绑包的根目录中。 (我说“毫不客气”,因为如果不同文件夹中有同名文件,它们会在这里发生冲突,您将无法解决导致的问题。)在我的示例中,RealDir 就是这种情况:部署的应用程序,RealDir 不再存在,icon2.png 与普通人群混在一起(可怕)。几乎不用说,“JustGroup”,纯粹的逻辑 Xcode 组,也被忽略了 - 无论如何它从来都不是一个真正的目录,只是 Xcode 用户的视觉帮助 - 而且 icon1.png 也在包根目录中。
-
“蓝色文件夹”,另一方面,即“添加文件夹的文件夹引用”表示的目录,实际上保留在app bundle目录结构中。这显然是蓝色文件夹的重点:它们为您提供了一种在部署的应用程序中创建目录结构的方法。我不确定最初的存在理由,但一个很好的用例是您有多个目录,其中包含具有相同名称的资源文件的替代版本,并且您希望您的应用程序能够在运行时在它们之间切换通过更改目录。无论如何,我的 FolderReference 中的 icon3.png 仍保留在已部署应用程序的我的 FolderReference 目录中。
- 这就是为什么 imageNamed: 无法使用“icon3”找到它,但可以使用“FolderReference/icon3”找到它
-
imageWithContentsOfFile 也可以使用 FolderReference 找到它,但只有在附加时,请记住使用上面的代码找到完整的包路径。 (这里的关键区别:在这种情况下,imageNamed 使用相对路径,而 imageWithContentsOfFile 始终使用绝对路径)。
为了澄清,这里是我的文件夹结构:
您在上面看到了我的 Xcode 项目导航器结构,这是它下面的文件系统目录:
最后,也许是最重要的,部署的包文件系统目录结构:
注意:我在我的 Mac 上的这个位置找到了这个:你会在一个类似的位置找到你的 - 你可能需要搜索一下才能找到哪个以丑陋 GUID 命名的子目录包含你的应用程序。
~/Library/Application Support/iPhone Simulator/5.1/Applications/4EB386B2-CD7E-4590-9757-18DDDEE6AF4F/ImageLoadingTest.app
我希望这会有所帮助。测试、探索并最终描述这对我很有帮助。