UIImage imageNamed需要pathForResource吗?

时间:2012-04-30 08:50:12

标签: iphone objective-c uiimage nsbundle

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

根据我的经验,我一直只是直接使用这个名字而且它一直都很好。我以为它会自动知道如何找到图像。有多重要或在什么情况下需要做更多的事情?

4 个答案:

答案 0 :(得分:59)

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

  

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

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

无论如何,关于一个真正的答案。

像往常一样,我在试图找到答案时发现了这个问题。我从来没有发现这个问题的文档或其他答案令人满意,所以我决定测试。

我的测试详情如下,但让我在这里总结一下结果。 简而言之,当使用imageNamed:加载图片时,它取决于你放置它们的位置:

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

  2. 如果您的图片位于附加到文件系统目录的组中,则通过"为添加的文件夹创建组"那么你仍然不必担心这个名字。

  3. 如果您的图片位于"蓝色"组,通过"创建文件夹引用以添加文件夹",然后您可以使用imageNamed加载它:通过指定相应的路径(巧合?)接受的答案上方。

  4. 如果您使用imageNamed:,imageWithContentsOfFile:的主要替代方法,您确实需要包含包路径的文件的完整路径,这意味着您需要知道Xcode导航器结构如何转换为您的路径中的路径捆绑目录结构。

  5. 这两种方法之间的其他重要区别:

    • imageNamed并不要求您指定文件类型扩展名, 仅仅是" icon"不是" icon.png",而imageWithContentsOfFile呢 需要完整的文件名
    • 这第一点有助于第二个功能:imageNamed会 通过在文件名中添加@ 2x,自动加载图像的视网膜版本(如果有)。所以,如果你要求" icon",在a 视网膜显示它将尝试加载" icon@2x.png"。 imageWithContentsOfFile不
    • imageNamed缓存图像:其中包含很多内容 围绕它的争议:如果你搜索SO或网络,你会发现 找到很多帖子建议你避免它,因为它没有 正确清除缓存。然而,这是几年前修复的,所以你 不用担心它无法清除缓存。你仍然 但是,需要担心它会缓存这个事实。如果你的 图像并且不经常加载,您将保存 内存通过从文件加载它们而不是缓存它们。这是 与泄漏无关:即使你没有泄漏,你仍然可以 设备上的内存有限,而您不想缓存 不必要的。这是经典的缓存权衡:还有什么呢? 在你的情况下重要吗?内存性能或CPU性能 (时间)。

    接下来我的测试。

    我所做的是创建一个简单的UITableView应用程序,其中包含3个简单的图标文件,使用不同的方法显示在表格的行中。这些图标在 Xcode 项目结构中的位置不同。注意强调Xcode。理解原始问题答案的关键是iOS应用程序中有三个完全不同的项目目录结构:您在Xcode导航器中看到的那个,同一个项目的文件系统上的那个你在Finder中看到了(右键单击Xco​​de导航器中的任何项目并选择"在Finder&#34中显示;),以及你很少看到的那个,"捆绑"已部署应用程序的目录结构。您也可以在Finder中看到最后一个 - 通过在〜/ Library / Application Support / iPhone Simulator中找到您的应用程序,然后深入到.app目录。我会在一分钟内向你展示我的照片。

    所以在我的应用程序中,我以不同的方式将所有三个图标png图像文件拖到Xcode中:

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

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

    3. icon3.png(一个目标),我也有一个单独的目录,我也拖了它 进入Xcode。只有这次我选择了第二个收音机选项"创建 任何添加文件夹的文件夹引用"。这创造了一个所谓的 "蓝色" Xcode中的一个组。更多关于以后的内容。一世 称这个组(和目录)" FolderReference"

    4. 以下是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:方法从应用程序包中加载图像。这意味着您不需要指定包位置,只需指定文件名。即便如此,只需要文件的基本名称。这里的文档有点薄,它应该清楚地表明它将图像从给定的文件路径 relative 加载到应用程序包根目录。

      • (这里是踢球者,注意这一点)关于捆绑目录的规则,是指您部署的应用程序包中的根目录。如果你去探索,这意味着在" .app"目录本身。那个与Xcode导航器中的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项目导航器结构,这里是它下面的文件系统目录: Finder Xcode project directory structure

      最后,也许最重要的是,部署的bundle文件系统目录结构: deployed bundle directory structure

      注意:我在Mac上的这个位置找到了这个:你会在类似的位置找到你的位置 - 你可能需要搜索一下才能找到哪个丑陋的GUID命名的子目录包含你的应用程序。

       ~/Library/Application Support/iPhone Simulator/5.1/Applications/4EB386B2-CD7E-4590-9757-18DDDEE6AF4F/ImageLoadingTest.app 
      

      我希望这会有所帮助。测试,探索,最后,描述它确实帮助了我。

答案 1 :(得分:5)

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

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

答案 2 :(得分:0)

我创建了一个新的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不是组文件夹Images。从项目中删除了png,创建了一个Images文件夹,将Wall1.png移动到该文件夹​​中。将现有文件Wall1.png添加到图像组。

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

图片为空

将图像/ Wall1更改为Wall1

跑出应用程序,显示繁荣图像1

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

答案 3 :(得分:-1)

试试这个。

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

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