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


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

"YourViewController"



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

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



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

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

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

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

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

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

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

关于如何让自己的应用国际化的具体方法,将在之后的文章进行描述。 

===============================================

bundle制作其实是前面制作静态库的一个衍生。


在静态库的制作中,很多时候我们的静态库也是带着文件,图片和多媒体资源的。


若只是直接加入到项目中也是可以,但是,考虑到方便管理(方便插件使用者的管理),我们希望把插件的资源文件打成一个包来管理。


比如,我们项目中有用到的银联支付插件。





这样我们直接添加xxxx.bundle文件到项目中就可以,这样在以后如果要删除的话直接删除一个xxx.bundle文件就行了。


当然有人也会说,那我直接在项目中新建一个group来管理也是一样的容易。


此刻, 我只能很装逼的说一句:这样,显得专业点么~。


你看three20啊,银联啊等等。整体项目目录相对看起来简约点。


 


bundle的制作。


1. 新建一个文件夹,然后将文件夹命名修改你要的文件夹名,并且加上后缀:xxx.bundle。


然后你就会看到文件夹变成了一个我们常见的bundle样式的文件夹。


 


2.加入文件资源,此时为了方便管理,我们 最好现在里面新建3种资源的文件夹




当然了,不创建也没关系,但是这个images文件夹最好创建,因为,我们会把所有的图片资源放在这里来方便管理。


然后添加点图片到images中。


 


3.把bundle文件加入到项目中


 




4.读取和使用文件。

UILabel *la = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 50, 50)];   

 

  la.text = @"陈凯";   

 

  NSString *image_url = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"nono.bundle/images/android.png"];   

 

  la.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:image_url]];



此时,因为以前我们获取UIImage对象大部分都是直接使用的api为:


[UIImage imageNamed:@"android.png"]


方法其实也是通过相对路径给我们找到了图片资源。


但是在我们自己制作的bundle文件夹的图片资源则不能使用该方法来找到了。


我们每次指定图片需要传入一个很长的地址,觉得比较麻烦。但是我们会发现,图片都是在xxx.bundle/images下面。


那么我们也可以使用宏或是类别来定义一个方法来简单到和[UIImage imageNamed:@"android.png"]一样。只需一个文件名就行了。


宏的表现可以参考three20下的


TTIMAGE(@"bundle://Three20.bundle/images/backIcon.png")

返回的就是一个image对象。


three20框架中其实是使用了scheme的思想,bundle://和document;//来加载不同文件夹下的资源。


加载自定义bundle文件夹下的图片最后就是根据


先获取应用的绝对路径 


mainbundle_path = [NSBundlemainBundle] resourcePath] ;

然后截取了bundle://后面的path 和mainbundle_path组装成最后的地址。


 


对于我们,简单的实现可以直接使用类别


-(UIImage*) imagesNamedFromCustomBundle:(NSString *)name   

 

  {   

 

      NSString *main_images_dir_path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"nono.bundle/images"];   

 

  //    NSAssert(main_images_dir_path, @"main_images_dir_path is null");   

 

      NSString *image_path = [main_images_dir_path stringByAppendingPathComponent:name];   

 

      return [UIImage imageWithContentsOfFile:image_path];   

 

  }


创建一个UIImage的类别,添加这个扩展的方法。