XCode ios iphone 资源文件管理 NSBundle mainBundle

来源:互联网 发布:兽血天龙网络连接 编辑:程序博客网 时间:2024/05/22 11:37

初学iOS开发的同学,不管是自己写的,还是粘贴的代码,或多或少都写过下面的代码

  

[[NSBundle mainBundle] pathForResource:@"someFileName" ofType:@"yourFileExtension"]; 

[YourViewController initWithNibName:"YourViewController" bundle:nil];

 

可是你知道这里的bundle到底是个啥玩意呢?!

Bundle简单地讲,就是一个内部结构按照标准规则组织的特殊目录

 

iOS的应用都是通过bundle进行封装的,对应的bundle类型是Application类型,平时我们通过XCode编译出来的Target(即我们开发的应用),其实就是一个Application类型bundle,即一个文件夹!但是Finder会把这个bundle当做一个文件显示给我们,其实是因为这个bundle自身也是一个package,而Mac系统会把所有的package当做一个文件来对待,显示给用户,从而防止用户误操作导致程序文件损坏或丢失。至于bundle和package有什么区别,就不在这里展开说明了,本文后面所说的bundle都会被Mac系统视为package。

 

现在我们已经知道了,原来我们开发的应用程序,最后都会成为一个bundle,那么就不难理解为什么很多资源文件加载大多是通过bundle来进行的了,从bundle进行文件加载实际就是通过应用自己所在的文件夹进行加载。

 

不过紧接着我们又会产生好几个疑问:

为什么不直接使用文件路径的方式来读取资源文件呢?

为什么还会存在pathForResource:ofType:这个方法,难道说我们在开发的时候还不能确定这些文件在哪儿吗?



事实上,我们是可以使用文件系统的路径进行资源文件的访问的,不过当我们要进行App的国际化的时候,我们需要自己去实现不同语言、地区情况下加载对应的文件,而在部分资源文件公用,部分需要国际化的时候,对开发人员来讲,代码维护起来尤为混乱。

而bundle对iOS开发者来讲,最大的方便就是可以非常简单地让自己的应用国际化,在不同的语言不同的地区,加载不同的资源文件,显示不同的语言文字,而实现这些只需要我们严格按照bundle的要求进行资源文件的存放即可,而不需要写大量代码判断地区语言。遵循的方法也很简单,只需要我们创建对应的"本地化文件夹"即可,例如我们要同时让图片"pic.png"在中文和英文下显示不同的内容,只需要创建两个本地化文件夹zh.lproj和en.lproj,分别放入同名但内容不同的"pic.png"即可。


   在ios的开发中,经常需要将一些资源文件(视频,音频,图片等)部署到ios设备中,但在默认情况下,系统会将所有的资源全部拷贝到mainBundle(全部纺织一个文件夹下) 目录下,即使你的资源是按文件夹来组织的。 
在使用ArcGIS API for iOS加载离线cache图片的过程中,这个问题非常明显,因为所有的cache图片都是按照分级规则组织好的图片,如果全部拷贝到mainBundle目录下有可能很多图片名称相同,同时也无法按照文件夹的规则去读取图片,因此需要在mainBundle 目录下以文件夹的方式来管理。 
解决这个问题很简单,只需要将需要拷贝的资源文件夹拖拽到xcode工程other source 目录下,如下图,此时会弹出一个对话框,默认是“recursively create groups for any add folders”,我们选择下面的一项“create folder references for any added folders” 点击add即可。 
XCode <wbr>ios <wbr>iphone <wbr>资源文件管理 <wbr>NSBundle <wbr>mainBundle 
添加以后 在xocde中可以看到对应的资源文件夹为蓝色,而不是黄色,如下图: 
XCode <wbr>ios <wbr>iphone <wbr>资源文件管理 <wbr>NSBundle <wbr>mainBundle  
这样,我们在使用[[NSBundle mainBundle] pathForResource:fileName ofType:@"jpg" inDirectory: dir ];的时候就可以通过文件夹路径去获取相关文件了。 
注意,请不要使用group或者add exist file的的方式来添加,否则使用pathForResource方法无法获取要想要的的文件。

XCode <wbr>ios <wbr>iphone <wbr>资源文件管理 <wbr>NSBundle <wbr>mainBundle


   XCode项目中的文件夹分成两类: group 和 directory reference, 分别是虚结构和实结构. 黄颜色的 group 是默认的格式, 它的结构和磁盘上的文件夹毫无关系, 仅仅表示资源的逻辑组织结构, 这在管理源文件是非常方便. 同一段代码可以被很多项目使用, 也可能只使用一个目录的部分文件, 它不需要被拷贝到当前项目中, 但可以在当前项目中保持一个清晰的逻辑结构. 而且引用头文件时不需要指明复杂的层次结构, 因为这些文件在XCode看来是 flat 的, 即它们处在同一层文件夹里. 

   但是 group 带来便利的同时也导致更加棘手的麻烦, 文件重名冲突问题; 尤其当你要使用上千个资源文件时, 这种问题已经极难避免; 而且, 资源文件一般是要拷贝到目标程序中的, 虽然它们在项目中可以有结构的组织, 但是复制到程序中时将会 flat 地输出到程序的根目录中, 这将是怎样的一个灾难! 同时, 如果你在外部向文件夹中加入了上百幅图片, 你不得不把它们再向xcode中加入一遍. 归根结底, 还要求助于我们传统的蓝色的 directory reference. 

   但是, XCode 偏偏还要抽风, 就是不让你用的安稳. 存在的问题有两点. 其一, Interface Builder(IB) 不支持directory reference! 尼玛, 几乎所有的 IDE 都采用的默认项目管理方式, 非但设成非缺省模式, 而且 IB 压根就不支持. 放狗去搜"interface builder directory reference", 答案只有一个, "it is impossible!" 其二, build 程序是, 资源只会 只增式拷贝! 什么意思? 当你在资源文件中加入一个图片时, ok, 没有任何问题; 可是当你试图删除哪怕修改一个资源时, no no no, you cannot do that! 所以当你调了半个小时还没明白, 卧槽, 图片明明换了, 怎么还是这个样子? 当然了, 解决方案是乖乖的 clean build directory, 然后再 build. 差异检测就这么难么? 感谢 David Frampton 为我们在这个问题上画了个较为圆满的句号: 在项目生成步骤中复制资源前增加一个脚本

Touch -cm ${SRCROOT}/(你的资源文件夹)

更新资源文件夹的 modification timestamp, 保证资源强制更新.

那么最终有没有好的解决方案涅?

完美的方式 没有

但有两个曲线救国的方针:

方案一:

同时维护 Real资源文件夹(directory reference)+Virtual资源文件夹(group) 前者是所有资源所处的目录, 为代码编程地加载资源使用; 后者只维护 IB 中使用的资源. 这种方式的缺点是, 后一个文件夹里的资源会在输出项目中存在两份, 增加程序体积.

方案二:

只维护一个 Real资源文件夹(directory reference), 在 IB 中使用嵌套路径加载资源; 在 XCode 开发时, 你无法从 IB 中看到加载的资源效果, 但在运行时就没有问题了.

鱼与熊掌, 不可兼得.

 

参考资料:

http://stackoverflow.com/questions/1812731/Iphone-interface-builder-moved-resources-to-sub-directory-now-ib-cant-see-th

http://maniacdev.com/2010/08/how-to-use-xcodes-folder-references/

http://majicjungle.com/blog/123/