【问题标题】:UIImage imageNamed requires pathForResource?UIImage imageNamed 需要 pathForResource?
【发布时间】:2012-05-09 23:38:22
【问题描述】:

在使用imageNamed 创建UIImage 时,使用NSBundle 方法pathForResource 搜索图像路径的必要性有多大?我看到的教程代码只是直接指定了图像的名称,然后代码会更加努力地首先找到路径。

根据我的经验,我一直只是直接使用该名称,而且它总是运行良好。我假设它自动知道如何找到图像。比这更重要或在什么情况下需要做更多的事情?

【问题讨论】:

  • Here 是一篇关于在代码中使用 imageNamed 的 SO 帖子,您可能也想阅读它。与您的问题没有直接关系,但我发现它很有帮助。

标签: iphone objective-c uiimage nsbundle


【解决方案1】:

根本没有 ...是原始问题的答案:

在使用 imageNamed 创建 UIImage 时,使用 NSBundle 方法 pathForResource 搜索图像路径的必要性有多大?

不多 .. 来自 Zoul 和来自 Ranga 的另一个接受的答案是如何正确。公平地说:如果您谈论的是应用程序包目录结构,或者图像位于 Xcode 中的“蓝色”文件夹中的(罕见)情况(稍后会详细介绍),它们是正确的,但不是大多数常见情况

无论如何,找到一个真正的答案。

像往常一样,我在尝试自己寻找答案时发现了这个问题。我从未找到令人满意的文档或此问题的其他答案,因此我决定进行测试。

我的测试细节都在下面,但让我在这里总结一下结果。 简而言之,当使用 imageNamed: 加载图像时,这取决于您将它们放在哪里:

  1. 如果您的图像位于项目的根目录中,即使组织在一个纯逻辑 Xcode 组中,那么不,您不需要 需要考虑路径:只是图像名称。

  2. 如果您的图像位于附加到文件系统目录的组中,通过“为添加的文件夹创建组”,那么您仍然不需要担心名字。

  3. 如果您的图像位于“蓝色”组中,该组通过“为添加的文件夹创建文件夹引用”附加到文件系统中的目录,那么您可以使用 imageNamed: 通过指定相对路径来加载它正如上面接受的答案所建议的(巧合?)。

  4. 如果您使用 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 中:

  1. icon1.png(一个时钟),我作为文件拖入Xcode项目的根目录, 然后我稍后在 Xcode 中创建了一个新组并将其拖入 那。该组不由文件中的任何目录表示 系统:这是一个纯 Xcode 组。因此它的名字是:“JustGroup”

  2. icon2.png(一只眼睛),我最初将我的文件系统放在名为的目录中 “RealDir”,我把整个目录拖到 Xcode 中,当 问,我选择了“为任何添加的文件夹创建组”选项。 这意味着 Xcode 中的 RealDir 组附加到一个真实的 文件系统中名为 RealDir 的目录(在我的项目目录中) 那个icon2.png就在那里。

  3. 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 也在包根目录中。

    • 这就是 imageNamed: 能够加载 icon2 的原因。

    • 还有为什么 imageWithContentsOfFile 无法在“RealDir/image2.png”中找到它:因为部署的应用程序中没有 RealDir 目录

  • “蓝色文件夹”,另一方面,即“添加文件夹的文件夹引用”表示的目录,实际上保留在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 

我希望这会有所帮助。测试、探索并最终描述这对我很有帮助。

【讨论】:

  • 这应该是答案,无论如何感谢发帖。
  • 这是一个超级有用的答案,并为我解决了这个问题。应该是公认的答案。赞成并感谢。
  • 我能问你在哪里找到你的“部署的捆绑文件系统目录结构”吗?我在“/Users/cdesign/Library/Application Support/iPhone Simulator/6.1/Applications/B458A3F5-5B21-49CD-B4D8-17E5189678FA”中找不到它,它只包含“Documents”、“Library”、“tmp”和“我的应用程序.app'。 'Documents' 只包含对应于 NSDocumentDirectory 的图像...
【解决方案2】:

文档说“该方法在应用程序的主包中查找具有指定名称的图像”,所以我说您始终可以只使用名称。唯一的例外可能是存储在子文件夹中的图像,尤其是当您拥有foo/image.pngbar/image.png 时。我不知道[UIImage imageNamed:@"foo/image"] 是否可行,但尝试起来很简单。

(在这些情况下有点令人困惑的是 Xcode 树中的组不对应于生成的应用程序包中的文件夹。它们的内容被一起粉碎到包的根目录,除非您使用蓝色文件夹引用代替一个普通的群体。)

【讨论】:

  • 实际上你是对的,它确实有效,但是(而且它很大但是)只有如果“foo”是你的包中的一个目录,因此是一个“蓝色” Xcode 中的文件夹。在最常见的情况下,您根本不需要“foo”。 (程序问题:如果你只有文档和猜测,你不应该回答,如果它不能解决你的问题,你也不应该接受答案 - 如果你有一个蓝色文件夹,那么一切都很好,如果没有,那么这对你没有用。)请参阅下面关于该主题的冗长论文
【解决方案3】:

我创建了一个新的 Xcode 项目(单一视图、AppDelelgate、ViewController 类、情节提要等)。 创建了一个图像组。 使用 Paintbrush 创建一个 16x16 png 文件 Wall1.png 并将其放入 Xcode 中的 Images 组(让 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]处添加断点;

图片为空

打开终端并将目录更改为我的项目,Wall1.png 不是组文件夹图像。从项目中删除了 png,创建了一个 Images 文件夹,将 Wall1.png 移动到该文件夹​​中。将现有文件 Wall1.png 添加到图像组中。

运行应用程序,图像仍然没有出现。

图片为空

将图像/Wall1 更改为 Wall1

运行应用程序,显示景气图像1

如果您为图像创建组,Xcode 不会创建相应的目录。如果您愿意,可以手动创建一个(我更喜欢将图像保存在单独的文件夹中)。使用 UIImage imageWithContentsOfFile 时不要指定图像文件的完整路径。

【讨论】:

    【解决方案4】:

    试试这个。

    [UIImage imageNamed:@"your directory path of image"]
    

    [UIImage imageNamed:@"Dir1/folder1/folder2/imagename.jpeg"]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多