.a文件图片 ios

2015-10-28 01:17:24 wangkun_510 阅读数 1960
  • 组件基础2

    掌握Vue.js基础知识; 掌握Vue.js核心功能; 掌握Vue.js实战技能;

    0人学习 刘宏强
    免费试看

制作.a

1、新建项目 –> Cocoa Touch Static Library
这里写图片描述

2、添加库需要包含的代码
这里写图片描述

3、将需要暴露的.h文件暴露出来,.m会自动编译到.a文件中
这里写图片描述

4、分别选择真机设备和模拟器,command + B编译,staticTest会从红色变成黑色。真机和模拟器环境下用的.a文件是分开的。
这里写图片描述

5、在“Show in Finder ”,可以看到编译生成的.a 和 暴露的.h文件。
这里写图片描述
这里写图片描述


Note:
- Debug-iphoneos 文件夹里面的东西是用在真机上的
- Debug-iphonesimulator 文件夹里面的东西是用在模拟器上的
- 如果 Scheme 是 Release 模式,生成的文件夹就以 Release 开头
调试版本 VS 发布版本
- 调试版本会包含完整的符号信息,以方便调试
- 调试版本不会对代码进行优化
- 发布版本不会包含完整的符号信息
- 发布版本的执行代码是进行过优化的
- 发布版本的大小会比调试版本的略小
- 在执行速度方面,发布版本会更快些,但不意味着会有显著的提升


当我们需要打包的.a文件里面用到了图片等资源文件。此时我们不该直接把resource文件夹拖进项目,而是建立.bundle文件,然后把图片等资源放进.bundle里面管理。
这里写图片描述
这里写图片描述
在其他项目中使用我们打包的.a文件时,只需要将.a文件和暴露的.h文件以及资源文件.bundle(有Xib时还需要拖Xib)拖进新项目即可使用。


  1. 如果想要使打包好的.a文件能同时在模拟器和真机上使用,需要将两个.a文件进行合并。在终端输入指令:
lipo -create ~/Debug-iphoneos/libstaticTest.a ~/Debug-iphonesimulator/libstaticTest.a -output ~/libstaticTest.a

即: lipo -create + 真机.a文件路径 + 模拟器.a文件路径 + -output + 合成.a文件的路径
PS:可以通过 lipo -info .a文件路径 指令查看.a的类型


调试.a

1、创建一个application工程,可以正常运行。
这里写图片描述

2、此时我们需要在这个工程里添加静态库进行调试,点击targets下面的+号,添加libriary
这里写图片描述
3、此时在工程里面会出现静态库的文件夹,在此文件夹下面添加需要打包静态库的代码即可。
这里写图片描述

4、使用静态库,只需要将需要暴露的头文件引入project的类里。同时需要配置targets -> build Phases 下的Target Dependencies 和Link Binary With Libraries 添加我们创建的静态库.a。
这里写图片描述

5、打包静态库只需要选中静态库编译即可。具体打包方法同上。
这里写图片描述

2014-03-19 10:39:06 kepoon 阅读数 38562
  • 组件基础2

    掌握Vue.js基础知识; 掌握Vue.js核心功能; 掌握Vue.js实战技能;

    0人学习 刘宏强
    免费试看

最近在做Apple的IOS开发,有开发静态库的需求,本身IOS的开发,只允许静态库或者Framework。在Xcode上没有找到允许编译,如同Android上的*.so和Win32上的dll这样的说法。不过Framework这样的框架,估计也是类似动态库的实现,不过没有具体研究过,后续继续深入研究。

我这个文档的静态库的开发是基于Xcode4.2和iOS SDK5.0编写的。Xcode4跟之前的Xcode3还是有不少的差别的。

下面就简单写一个静态库和一个调用静态库的例子。

静态库的编写:

1.静态库工程的建立:

Xcode New一个新的project,选择IOS下面的Framework&Library,下面有一个Cocoa Touch Static Library。直接next去建立一个Print这样的工程。


2.工程建立

我们添加很简单的"- (void)printA;"和"+ (void)printB;"的方法,这个方法的实现也是很简单的,在*.m文件中的实现就是一个"NSLog(@“”);"这样我们编译出来的libstaticlib就可以被其他的IOS工程进行调用了。这块注意一下,目前我们的Print->iOS Device



3.编译前准备

这里分release与debug版本,需要设置一下


4.OK,编译

我们可以在Products下面找到我们编译生成的libstaticlib.a这个文件。

注意未编译前为红色:左                             编译后为黑色: 右

       

5.ok

在右边 这个文件上右键Open In Finder。这时候我们打开了一个文件夹,里面有一个libPrint.a。后面我们继续编写一个调用这个libPrint.a的App。但是这个App在编译时候会出错,通过这个错误的解决,说明Xcode的一些编译相关的东西。这里,我们在command下面根据路径找到这个文件,用这个非常重要的命令查看一下这个lib的信息!

打开终端写入如下命令:这是什么?这就是所在的路径 

以下均是在自己的mac上的路径。你需要将/Users/pjk1129/Library/Developer/Xcode/DerivedData/Print-dgfkluumuexoxhcapzidtsmdgqcj/Build/Products/ 替换成你的路径。

cd /Users/pjk1129/Library/Developer/Xcode/DerivedData/Print-dgfkluumuexoxhcapzidtsmdgqcj/Build/Products/  

我们手动打开这个路径:可以看到如下信息:Release-iphoneos


这个是给真机用的,那我们要给模拟器和真机封装的静态库应该都能用才好。这个下面介绍!!!!!  


然后再在终端 打开这个文件:cd /Users/user/Library/Developer/Xcode/DerivedData/UItab-dbvoszbzpavyglaboxgflvrnzfce/Build/Products/Debug-iphoneos

命令是:lipo -info libPrint.a,可以看到显示的结果是:Arch是  Arm7。下面我会具体介绍一下。


6.建立一个调用这个libPrint.a的应用

应用就很简单了,我们添加刚才libPrint.a的*.h文件。 然后在这个工程的Build Phases的Link Binary With Library里面添加我们刚才拷贝出来的那个libPrint.a。



7.插入了h和a文件后

我们就可以在control里面调用这个libPrint.a 函数了。

#import "AstroDiskAppDelegate.h"

#import "Print.h"


@implementation AstroDiskAppDelegate


@synthesize window = _window;


- (void)dealloc

{

    [_window release];

    [_viewController release];

    [super dealloc];

}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

    

    //调用libPrint.a

    [Print printB];

    Print  *print = [[[Print alloc] init] autorelease];

    [print printA];


    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    [self.window makeKeyAndVisible];

    return YES;

}



8.OK,编译运行这个应用程序。

编译出现错误了。这个就是这篇文档的关键了。主要就是为了介绍编译静态库相关的东西。



9.可以看到undefine symbols for architecture i386这样的错误。

其实这个错误原因很简单,就是因为,我们用错了编译出来的libUITab.a lib,在模拟器里面,我们需要的是基于i386构架编译的static lib,但是这个a文件,大家还记得前面说的arm6 arm7构架的么。这个a其实是在iphone这个arm构架上运行的代码。其实show in finder指向的是一个ios device的库,并不是i386模拟器下的库。那如何编译i386的库呢?看见第二张图片的Print>IOS Device了么?我们将这个iOS Device修改成iPhone5.0 Simulator。在进行编译,这样就可以编译出i386下面的库。这个时候我们show in finder打开的文件夹还是ios device下的库。我们最好自己去那个目录下看一下。这里我们用command去查看了一下目录情况,如下:可以看到一个iphoneos的目录和一个simulator的目录。


然后我们再看看这个目录与第4条所示的目录有什么不同! 同样也有一个libPrint.a文件。



10.错误原因分析

Release-iphoneos里面的是基于arm6 arm7编译出来的库文件。Release-iphonesimulator文件夹下面的是基于i386编译出来的文件。

11.合并.a文件,制作通用静态库

这二个库一个是用于真机运行的一个是用于模拟器运行的.其实我们可以利用lipo将这二个文件打包成一个通用的a文件。命令如下:

/Users/user/Library/Developer/Xcode/DerivedData/UITab-dgfkluumuexoxhcapzidtsmdgqcj/Build/Products替换成你的路径。 

/Users/user/Desktop/libPrint.a替换成合并后的路径。 

lipo -create /Users/pjk1129/Library/Developer/Xcode/DerivedData/Print-dgfkluumuexoxhcapzidtsmdgqcj/Build/Products/Release-iphonesimulator/libPrint.a  /Users/pjk1129/Library/Developer/Xcode/DerivedData/Print-dgfkluumuexoxhcapzidtsmdgqcj/Build/Products/Release-iphoneos/libPrint.a  -output /Users/pjk1129/Desktop/libPrint.a


12.打包以后的库文件,我们查看信息

然后打入如下命令:lipo -info /Users/pjk1129/Desktop/libPrint.a 

可以看到如下信息:


如上,你已经看到了,它具备了i386和arm7的条件。 现在我们这个静态库,支持的构架已经是armv7 i386了。


13.ok,经过上述步骤后

这个通用库生成后,我们将原来,调用这个库进行替换一下,在进行编译,成功编译,运行结果如下所示:


from:http://blog.csdn.net/pjk1129/article/details/7255163


2017-05-15 17:27:38 pangshishan1 阅读数 8837
  • 组件基础2

    掌握Vue.js基础知识; 掌握Vue.js核心功能; 掌握Vue.js实战技能;

    0人学习 刘宏强
    免费试看

引言

在开发中.framework静态库还是比较常见的,比如:SDK,公司间的代码合作等。我们可以把一些不愿意让别人见到的代码,用静态库的方式把它隐藏起来,只留下.h文件显示方法供编程人员使用。而.a文件出了静态库本身外,还需要引入.h文件,而.framework就不需要如此,由于.framework的方便性所以一般情况下我们见到的较多。

什么是库

库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。
iOS中的静态库有 .a 和 .framework两种形式;动态库有.dylib 和 .framework 形式,后来.dylib动态库又被苹果替换成.tbd的形式。

静态库与动态库的区别

静态库和动态库是相对编译期和运行期的:静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在。

Bundle文件

Bundle文件可以用于存放资源文件,可用于多人合作开发,避免资源重名。里面可以存储xib文、资源图片等。Bundle文件是静态的,不进行编译的。所以使用Bundle中的资源,就需要找到相应的资源路径。另外,我看别人博客上是说,.a文件中是无法用Bundle文件的,只能另存一个文件;Framework静态库可以用Bundle文件;我也没试过,请试过的小伙伴留言告诉我,我就偷个懒,嘿嘿

总结:同一个静态库在不同程序中使用时,每一个程序中都得导入一次,打包时也被打包进去,形成一个程序。而动态库在不同程序中,打包时并没有被打包进去,只在程序运行使用时,才链接载入(如系统的框架如UIKit、Foundation等),所以程序体积会小很多,但是苹果不让使用自己的动态库,否则审核就无法通过。

一、创建 .a 静态库

1. 新建工程。比如我们的工程名叫PSSTest,那么我们创建的.a静态库的名字最好就是前面加个lib,如libPSSTest.a。

  • 新建工程 (选中xcode,按commond + shift + N)
    图

  • 此时工程目录是这个样子,.a文件还没有被创建,因此是红色的
    图

  • 你可以把图中 libPSSTest.h.m 换成你自己要生成库的文件(可以是多个),在这里我就不换了,就用这两个文件,我们在.h文件中添加一个方法+sayHello,并在.m中实现它

// 一定要记得在.h中声明哦
+ (void)sayHello
{
    NSLog(@".a静态库:Hello, world!");
}

2. 添加Headers


  • 按照下图顺序进行操作
    图
    图
    图
    图
    图

这里需要注意的是暴露出来的头文件中import的其他类也得添加到public中暴露出来。
如果不想将import的类暴露出来,那么在头文件中用@class 然后在对应的.m文件中再import。
总之
1. 你再外面用到的类,一定要暴露出来;
2. 你暴露出来的类,头文件中导入的类也一定是暴露出来的
3. 如果提示导入头文件报错,找不到文件,找不到谁暴露谁就对了

3. 进行打包前的一些配置

  • 设置编译模式,打开xcode菜单Product -> Scheme -> Edit Scheme,改成release模式,如下图
    图

  • 编译机器的选择,如下图,一定要选择NO。(如果选择yes,生成部分机型,选择NO则适配所有机型,想了解更多,请自行百度,总之,选NO就对了)
    图

4. 接下来,我们进行打包

操作简述:
1. 在真机情况下编译 (Generic iOS Device),并记录下.a文件的绝对路径
2. 在模拟机情况下编译(随便吧,别贱嗖嗖的用iPhone4,虽然我也没试过有没有问题吧,有兴趣可以试试[emj坏笑]),并记录下.a文件绝对路径
3. 用命令行合并1、2部记录的文件,到新的.a文件,名字最好取开始我们取的名字吧,命令行:lipo -create 文件1路径 文件2路径 -output 最终文件路径
4. 把你要暴露的.h文件和你已经生成的.a文件搞到一个文件夹里,这个文件夹就可以直接拖到工程里用啦

4.1 在真机情况下编译 (Generic iOS Device),并记录下.a文件的绝对路径
4.1

4.2 在模拟机情况下编译,并记录下.a文件绝对路径,本操作和上步操作一模一样,只不过需要选择一个模拟器,随便选吧,我是选的iPhone7P,不截图了

4.3 使用命令行,合并刚刚记录的两个路径,到另一个路径,例如:

lipo -create /Users/xxxxx/Library/Developer/Xcode/DerivedData/libPSSTest-bmfbhsxiqeajiigltpqjlxhhpjjh/Build/Products/Release-iphoneos/liblibPSSTest.a空格/Users/shanhexia/Library/Developer/Xcode/DerivedData/libPSSTest-bmfbhsxiqeajiigltpqjlxhhpjjh/Build/Products/Release-iphonesimulator/liblibPSSTest.a -output /Users/shanhexia/Desktop/libPSSTest.a

我是把合成之后的.a文件放到桌面上了

4.4 也是最后一步,把我们刚合成的.a文件和想要暴露的.h文件,弄到一个文件夹下
新建一个文件夹,取名libPSSTest,把文件复制粘贴进来,如下图
图

4.5 创建.a静态库就已经创建完了,我们来试试吧,导入刚刚4.4创建的文件夹,导入头文件,调用方法看看有没有打印
看,我们成功了

4.6 补充:

  1. category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。
  2. 如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。

二、创建.Framework静态库

1. 新建工程。比如我们的工程名叫PSSFramework

  • 新建工程 (选中xcode,按commond + shift + N)
    图

  • 添加文件到工程,并且在PSSFramework.h文件中导入接口文件
    图片.png

  • 在PSSObject中添加+sayHello方法,并在.m中实现

// 一定要在`.h`中暴露方法哦
+ (void)sayHello
{
    NSLog(@".framework: Hello, world!");
}

2. 添加Headers

  • 这一步和创建.a的时候一模一样,请往上翻。不过跟.a不同的是,貌似它里面本来就有Headers了,但是只给你暴露了一个.h文件,需要多暴露的话再自己拖吧

3. 打包前的一些配置

  • 设置编译模式,打开xcode菜单Product -> Scheme -> Edit Scheme,改成release模式,如下图(这一步和生成.a一样,我就借用图了)
    图

  • 编译机器的选择,如下图,一定要选择NO。(这一步和生成.a一样,我就借用图了)
    图

  • 修改生成的Mach-O格式(很重要)

图片.png

4. 打包Framework (合并模拟器版framework和真机版framework)

  • 分别在真机(Generic iOS Device)和模拟器编译,这次不用记录路径,一会我会标出合并哪两个文件
    注意: 合并的命令同上面相似,不同之处是:framework静态库合并的不是framework,而是framework下的一个二进制文件,即下图中我标出来的文件。
    lipo -create 第一个framework下二进制文件的绝对路径 第二个framework下二进制文件的绝对路径 -output 最终的二进制文件路径。
    图片.png
    图片.png

  • 接下来我们进行合并,我们把新合并的二进制文件放到Release-iphoneosRelease-iphonesimulator同一个文件夹下

    命令行如下
    lipo -create /Users/xxxxx/Library/Developer/Xcode/DerivedData/PSSFramework-ehyytcfdvluxetbnmqcfzosxrbtu/Build/Products/Release-iphoneos/PSSFramework.framework/PSSFramework /Users/shanhexia/Library/Developer/Xcode/DerivedData/PSSFramework-ehyytcfdvluxetbnmqcfzosxrbtu/Build/Products/Release-iphonesimulator/PSSFramework.framework/PSSFramework -output /Users/shanhexia/Library/Developer/Xcode/DerivedData/PSSFramework-ehyytcfdvluxetbnmqcfzosxrbtu/Build/Products/PSSFramework

  • 图片.png

  • 通过上一步,我们已经把我们要的Framework搞到桌面上了,接下来我们就试试能不能用吧。将Framework拖进工程,导入框架,调用方法,看看有没有打印

    我试了,确实是能用,不截图了

三、Bundle文件的使用

1. 创建Bundle

桌面上创建一个文件夹,把文件夹的后缀改为. bundle这时他就变成一个bundle文件了,这时我们右键显示包内容就可以把对应的图片资源等放进文件中,然后把他丢进工程中就可以使用了。

2. 使用方法 (亲测可用)

图片.png



结束语

实际上,在项目中,我们用别人的Framework.a比较多一些,开发自己的项目的时候,我倒是没怎么用到过,但是公司如果希望一部分代码需要保密,是可以用这种方式的。或者你开发了一个功能,不想开源,也可以这样搞(虽然应该可以反编译,反正我不会),但是我不推荐;毕竟大家把自己的代码开源可以互相促进彼此的成长嘛,嘿嘿^_^

如果觉得写得还行,点个Star呗
同时也欢迎评论中指出本文存在的bug,或者疑问,互相促进!
作者邮箱:pangshishan@aliyun.com
github地址:https://github.com/Pangshishan
qq/微信: 704158807

2016-11-16 13:41:28 lizhilin_vip 阅读数 16735
  • 组件基础2

    掌握Vue.js基础知识; 掌握Vue.js核心功能; 掌握Vue.js实战技能;

    0人学习 刘宏强
    免费试看

一、iOS中的沙盒机制

iOS应用程序只能对自己创建的文件系统读取文件,这个独立、封闭、安全的空间,叫做沙盒。每个ios应用都有自己的应用沙盒,应用沙盒就是文件系统目录,与其他应用的文件系统隔离。它一般存放着程序包文件(可执行文件)、图片、音频、视频、plist文件、sqlite数据库以及其他文件。每个应用程序都有自己的独立的存储空间(沙盒)一般来说应用程序之间是不可以互相访问的,在ios8中已经开放访问,模拟器沙盒的位置路径:/User/userName/Library/Application Support/iPhone Simulator;当我们创建应用程序时,在每个沙盒中含有三个文件,分别是Document、Library(下面有Caches和Preferences目录)和temp。
应用程序包:包含所有的资源文件和可执行文件。


二、对Document、Library(下面有Caches和Preferences目录)和temp做简单介绍

1.Document:一般需要持久的数据都放在此目录中,可以在当中添加子文件夹,iTunes备份和恢复的时候,会包括此目录。

2.Library:设置程序的默认设置和其他状态信息,iTunes会自动备份该目录,例如杂志、新闻、地图应用使用的数据库缓存文件和可下载内容应该保存到这个文件夹。一般可以重新下载或者重新生成的数据应该保存在 <Application_Home>/Library/Caches 目录下面。
Libaray/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除。一般存放体积比较大,不是特别重要的资源。 
Libaray/PreferencePanes:保存应用的所有偏好设置,ios的Settings(设置)应用会在该目录中查找应用的设置信息,iTunes会自动备份该目录。

3.temp:创建临时
文件的目录,当iOS设备重启时,文件会被自动清除,只是临时使用的数据应该保存到 <Application_Home>/tmp 文件夹。iCloud 不会备份这些文件,下次启动应用自动删除。


三、获取沙盒路径

//Home目录
NSString *homeDirectory = NSHomeDirectory();
    
//Document目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
    
//Cache目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
    
//PreferencePanes目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
    
//Libaray目录NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
    
//tmp目录   
NSString *tmpDir = NSTemporaryDirectory();


四、文件夹操作(文件夹有:带扩展名.exe或者不带后缀两种)

1.创建文件夹

沙盒文件夹操作使用系统Foundation框架下的NSFileManager文件操作类实现。在沙盒中新建文件夹,需指定新建文件夹的绝对路径,然后手动创建。并且要保证新建文件夹的上级路径已经存在,否则需要先创建上级文件夹路径。文件夹的创建使用createDirectoryAtPath方法。

新建文件夹代码:

//判断createPath路径文件夹是否已存在,此处createPath为需要新建的文件夹的绝对路径  
if ([[NSFileManager defaultManager] fileExistsAtPath:createPath]) {   
    //文件夹已存在
    return;   
} else {   
    //创建文件夹  
    [[NSFileManager defaultManager] createDirectoryAtPath:createPath withIntermediateDirectories:YES attributes:nil error:nil];    
} 

其中creatPath的结构:沙盒路径\文件夹名.exe(或者沙盒路径\文件夹名),后面其他路径类似;(注意这两种方法一种生成带后缀.exe的文件夹,一中生成不带后缀名的文件夹,即使沙盒路径\文件夹名部分相同,也不是同一个文件夹

PS:如何保证新建文件夹的父亲文件夹已经存在(截取父文件夹路径验证),iOS提供了许多字符串路径的处理方法(以前是在Foundation框架的NSPathUtilities.h中,现在可用字符串直接调用)。  
+(NSString*)pathWithComponents:components 根据components中的元素构造有效路径
-(NSArray*)pathComponents 析构路径,获得组成此路径的各个部分
-(NSString*)lastPathComponent 提取路径的最后一个组成部分
-(NSString*)pathExtension 从路径的最后一个组成部分中提取其扩展名
-(NSString*)stringByAppendingPathComponent:path 将path添加到现有路径的末尾
-(NSString*)stringByDeletingLastPathComponent 删除路径的最后一个组成部分
-(NSString*)stringByDeletingPathExtension 从文件的最后一部分删除扩展名

其他方法可以搜索NSPathUtilities的用法自行查


2.删除文件夹

删除文件夹,需先判定该文件夹是否存在(使用fileExistsAtPath方法),如果存在,执行删除操作(使用removeItemAtPath)

if([[NSFileManager defaultManager] fileExistsAtPath:pathFull])//如果存在临时文件的配置文件 
{   
    [[NSFileManager defaultManager]  removeItemAtPath:pathFull error:&error];   
}  

3.移动文件夹

文件夹移动需要两个参数,文件夹原绝对路径与目标绝对路径。使用moveItemAtPath 方法实现

移动文件夹代码:

NSFileManager *fileManager =[NSFileManager defaultManager]; 
// prePath 为原路径,cenPath 为目标路径  
if([fileManager moveItemAtPath:prePath toPath:cenPath error:&error]) {   
    NSLog(@"移动文件成功");   
} else {   
    NSLog(@"移动文件失败");   
} 

PS:文件夹移动需要注意的是,要确保目标路径中除了目标文件夹之外的路径确实存在。否则移动到一个还没有创建的文件夹下,是会失败的,这和创建文件夹是一样的。

4.重命名文件夹

重命名文件夹也需要两个参数,原绝对路径与目标绝对路径,用了一个偷换概念的方式来实现,其实用的是移动文件夹的方法。不赘述。


5.获取目录下的所有文件名称(包括文件夹与文件)

//fileNameList中即为该imagesFolder文件夹下的所有文件的名称数组  
NSArray *fileNameList=[[NSFileManager defaultManager]  
contentsOfDirectoryAtPath:imagesFolder error:nil];  

五、文件操作

1.写入文件

写入文件需要首先判定该文件的父亲文件夹是否存在,存在则可以进行写入,否则需首先创建父亲  路径。使用writeToFile方法。写入文件的同时,系统会自动创建文件。

一般数据类型,比如数组、字典、NSData、NSString都可以直接调用writeToFile方法写入文件。

代码例子:

 [arrayA writeToFile:filePath atomically:YES];  

也可以手动创建文件:

NSFileManager *fileManager =[NSFileManager defaultManager];  
[fileManager createFileAtPath:myPath contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];

myPath例如:@"/Users/ibokan/Desktop/login.text"


2.读取文件

如果用户知道文件内容的数据类型比较规整,则可以直接读取文件内容到标准数据结构中。

NSArray *arrayA = [[NSArray alloc] initWithContentsOfFile:filePath];

filePath例如:@"/Users/ibokan/Desktop/login.plist"

PS:或许有些时候,需要用到混合数据的写入与读取,可以使用NSMutableData实现。(其它数据类型转化为data存入,再以data形式读取后转化为原来数据类型)


3.NSFileManager一些文件方法

创建一个文件并写入数据
- (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr;
从一个文件中读取数据 
- (NSData *)contentsAtPath:(NSString *)path;
移动文件         
- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **) error;
复制文件 
- (BOOL)copyItemAtPath:(NSString *)scrPath toPath:(NSString *)dstPath error:(NSError **) error;
比较两个文件的内容是否一样 
- (BOOL)contentsEqualAtPath:(NSString *)path1 andPath:(NSString *)path2;
文件是否存在
- (BOOL)fileExistsAtPath:(NSString *)path;
移除文件 
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **) error;

4.NSFileManager一些方法代码举例

//创建文件管理  
NSFileManager *fileManager = [NSFileManager defaultManager];     
NSString *path = [NSHomeDirectory( )  stringByAppendingPathComponent:@"holyBible.txt"];                                         NSString *text = @"abcdefg";   
//将字符串转成NSData类型   
NSData *data = [text dataUsingEncoding: NSUTF8StringEncoding];   
//写入文件   
BOOL success = [fileManager createFileAtPath:path contents:data attributes:nil];  
  
//NSFileManager-读取内容   
NSData *fileData = [fileManager contentsAtPath:filePath];                                     
NSString *content = [[NSString alloc] initWithData:fileData dataUsingEncoding: NSUTF8StringEncoding];  
//NSData-读取内容                                                                                            
NSString *filePath = [path stringByAppendingPathComponent:@"holyBible.txt"];       
NSData *data = [NSData dataWithContentOfFile:filePath];  
//NSString-读取内容   
NSString *filePath = [path stringByAppendingPathComponent:@"holyBible.txt"];       
NSString *content = [[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];  
                                                                                              
//移动文件(重命名)  
NSString *toPath = [NSHomeDirectory( ) stringByAppendingPathComponent:@"hellogod/newTestament.txt"];  
[fileManager createDirectoryAtPath:[toPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];//先建立父文件夹  
NSError *error;                                                                                               
BOOL isSuccess = [fileManager moveItemAtPath:filePath toPath:toPath error:&error];  
  
//复制文件(重命名)  
NSString *copyPath = [NSHomeDirectory( ) stringByAppendingPathComponent:@"备份/Old Testament.txt"];                              [fileManager createDirectoryAtPath:[toPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];//先建立父文件夹                                                     
BOOL success = [fileManager copyItemAtPath:toPath toPath:toPath error:nil];  
  
//删除文件、获取文件大小  
//判断文件是否存在和删除文件                                                                                
if([fileManager fileExistsAtPath:copyPath])  
{                        
 if ([fileManager removeItemAtPath:copyPath])    
 {                                                                                  
  NSLog(@"remove success");  
 }                                                                                                                    
}  
  
//获取文件大小    
NSFileManager *fileManager = [NSFileManager defaultManager];                          
//获得文件的属性字典  
NSDictionary *attrDic = [fileManager attributesOfItemAtpath:sourcePath error:nil];    
NSNumber *fileSize = [attrDic objectForKey:NSFileSize];    
   
//获取目录文件信息  
NSFileManager *fileManager = [NSFileManager defaultManager];                           
NSString *enuPath = [NSHomeDirectoty( ) stringByAppendingPathComponent:@"Test"];                                                NSDictionaryEnumerator *dirEnum = [fileManager enumeratorAtPath:enuPath];       
NSString *path = nil;                                                                                        
while ((path = [dirEnum nextObject]) != nil){                              
NSLog(@"%@",path);                                                                                         
}  

六、几个可能会用到的例子

1.获取应用程序程序包中资源文件路径的方法以及复制资源包中文件到沙盒:

//例如获取程序包中一个图片资源(apple.png)路径的方法:  
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@”apple” ofType:@”png”];  
UIImage *appleImage = [[UIImage alloc] initWithContentsOfFile:imagePath];  
//代码中的mainBundle类方法用于返回一个代表应用程序包的对象。 

有时候我们建数据库文件,不喜欢用代码直接建,可能会用火狐的工具,建完之后拖入工程,但是这是数据库不可进行增删改操作,只有放入沙盒,所以要把它复制到沙盒里面,代码如下:

//沙盒目标路径  
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];  
NSString *sqlFilePath = [docPath stringByAppendingPathComponent:@"ShuJuKu.sqlite"];  
  
//原始项目路径  
NSString *orignFilePath = [[NSBundle mainBundle] pathForResource:@"ShuJuKu" ofType:@"sqlite"];  
NSFileManager *fm = [NSFileManager defaultManager];  
//如果doc下没有数据库,从bundle里面拷贝过来  
if([fm fileExistsAtPath:sqlFilePath] == NO) {  
    NSError *err = nil;  
    //如果拷贝失败  
    if([fm copyItemAtPath:orignFilePath toPath:sqlFilePath error:&err] == NO) {  
        NSLog(@"拷贝失败,原因: %@",[err localizedDescription]);  
        return nil;  
    }  
}  

2.举一个图片存入沙盒以及从沙盒读取的例子

//图片存储到沙盒中  
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);  
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@“gg.png"]];// 保存文件的名称  
[UIImagePNGRepresentation(myImage)writeToFile: filePath atomically:YES];  
//myImage就是那张要保存的图片  
  
//读取  
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);  
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"myImage.png", (int)current]];// 保存文件的名称  
UIImage *img = [UIImage imageWithContentsOfFile:filePath];

PS:有时候我们需要批量存储图片的时候,可以把图片转化为NSData类型存入plist文件,然后把plist文件存入沙盒(可能会导致文件过大);也可以把图片存入沙盒,然后把图片存放路径存入plist,之后再把plist文件存入沙盒。

2015-01-25 15:54:03 LVXIANGAN 阅读数 20590
  • 组件基础2

    掌握Vue.js基础知识; 掌握Vue.js核心功能; 掌握Vue.js实战技能;

    0人学习 刘宏强
    免费试看

一、什么是库?

库是共享程序代码的方式,一般分为静态库和动态库。

二、静态库与动态库的区别?

静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。

动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

三、iOS里静态库形式?

.a和.framework

四、iOS里动态库形式?

.dylib和.framework

五、framework为什么既是静态库又是动态库?

系统的.framework是动态库,我们自己建立的.framework是静态库。

六、a与.framework有什么区别?

.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。

.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。

.a + .h + sourceFile = .framework。

建议用.framework.

七、为什么要使用静态库?

方便共享代码,便于合理使用。

实现iOS程序的模块化。可以把固定的业务模块化成静态库。

和别人分享你的代码库,但不想让别人看到你代码的实现。

开发第三方sdk的需要。

八、制作静态库时的几点注意:

1 注意理解:无论是.a静态库还.framework静态库,我们需要的都是二进制文件+.h+其它资源文件的形式,不同的是,.a本身就是二进制文件,需要我们自己配上.h和其它文件才能使用,而.framework本身已经包含了.h和其它文件,可以直接使用。

2 图片资源的处理:两种静态库,一般都是把图片文件单独的放在一个.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一个文件夹,把它改名为.bundle就可以了,右键,显示包内容可以向其中添加图片资源。

3 category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。

4 如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。

Xcode封装.Bundle文件

阅读数 21974