1.应用沙盒
出于安全考虑,iOS 系统的沙盒机制规定每个应用都只能访问当前沙盒目录下面的文件(也有例外,比如在用户授权情况下访问通讯录,相册等),这个规则展示了 iOS 系统的封闭性。在开发中常常需要数据存储的功能,比如存取文件,归档解档等。
1.1 沙盒目录结构
每个 APP 的沙盒下面都有相似目录结构,如图:
NSString *path = NSHomeDirectory();
复制代码
上面的代码得到的是应用程序目录的路径,在该目录下有三个文件夹:Documents、Library、temp 以及一个 .app 包。该目录下就是应用程序的沙盒,应用程序只能访问该目录下的文件夹。
-
MyApp.app
该目录包含了应用程序本身的数据,包括图片、plist文件、nib文件、国际化文件和可执行文件等。程序启动以后,会根据需要从该目录中动态加载代码或资源到内存,这里用到了懒加载的思想。为了防止被篡改,应用在安装的时候会将该目录签名。该路径下的文件不会被 iTunes 备份。
-
Documents
我们可以将应用程序的数据文件保存在该目录下。不过这些数据类型仅限于不可再生的数据,可再生的数据文件应该存放在 Library / Cache 目录下。该路径下的文件会被 iTunes 备份。
-
Documents / Inbox
该目录用来保存由外部应用请求当前应用程序打开的文件。比如我们的应用叫 A,向系统注册了几种可打开的文件格式,B 应用有一个 A 支持的格式的文件 F,并且申请调用 A 打开 F。由于 F 当前是在 B 应用的沙盒中,我们知道,沙盒机制是不允许 A 访问 B 沙盒中的文件,因此苹果的解决方案是讲 F 拷贝一份到 A 应用的 Documents / Inbox 目录下,再让 A 打开 F。该路径下的文件会被 iTunes 备份。
-
Library
苹果建议用来存放默认设置或其它状态信息,这个目录下有两个子目录:
-
Caches
主要是缓存文件,用户使用过程中缓存都可以保存在这个目录中。前面说过,Documents 目录用于保存不可再生的文件,那么这个目录就用于保存那些可再生的文件,比如网络请求的数据。鉴于此,应用程序通常还需要负责删除这些文件。该路径下的文件不会被 iTunes 备份。
-
Preferences
应用程序的偏好设置文件。我们使用 NSUserDefaults 写的设置数据都会保存到该目录下的一个 plist 文件中,这就是所谓的写道 plist 中。该路径下的文件会被 iTunes 备份。
-
-
tmp
各种临时文件,保存应用再次启动时不需要的文件。而且,当应用不再需要这些文件时应该主动将其删除,因为该目录下的东西随时有可能被系统清理掉,目前已知的一种可能清理的原因是系统磁盘存储空间不足的时候。该路径下的文件不会被 iTunes 备份。
1.2 获取各种文件目录的路径
获取目录路径的方法:
//获取沙盒主目录路径
NSString *homeDir = NSHomeDirectory();
//获取Documents目录路径
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//获取Library的目录路径
NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
//获取Caches目录路径
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
//获取tmp目录路径
NSString *tmpDir = NSTemporaryDirectory();
复制代码
NSSearchPathForDirectoriesInDomains方法中有三个参数:
-
directory
NSSearchPathDirectory 类型的 enum 值,表明我们要搜索的目录名称,比如这里用 NSDocumentDirectory 表明我们要搜索的是 Documents 目录。如果我们将其换成 NSCachesDirectory 就表示我们搜索的是 Library / Caches 目录。
-
domainMask
NSSearchPathDomainMask 类型的 enum 值,指定搜索范围,这里的 NSUserDomainMask 表示搜索的范围限制于当前应用的沙盒目录。还可以写成 NSLocalDomainMask(表示 /Library)、NSNetworkDomainMask(表示 /Network)等。
-
expandTilde
BOOL 值,表示是否展开波浪线 ~。我们知道在iOS中 ~ 的全写形式是 /User/userName,该值为 YES 即表示写成全写形式,为 NO 就表示直接写成“~”。
获取应用程序程序包 (Myapp.app) 中资源文件路径的方法:
NSLog(@"%@",[[NSBundle mainBundle] bundlePath]);
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"apple" ofType:@"png"];
UIImage *appleImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
复制代码
2.plist 归档
“归档”意思是持久化存储数据。plist 文件是一种 XML 格式的文件,拓展名为 plist。如果对象是 NSString、NSDictionary、NSArray、NSData、NSNumber 等类型,就可以使用 writeToFile:atomically: 方法直接将对象写到属性列表文件(plist文件)中。特别注意的是 plist 文件不能存储对象。
//读取plist文件
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"contact" ofType:@"plist"];
NSArray *allContacts = [NSArray arrayWithContentsOfFile: plistPath];
for (NSDictionary *dict in allContacts) {
NSString *name = dict[@"name"];
NSString *phoneNumber= dict[@"phoneNumber"];
NSString *address = dict[@"address"];
NSLog(@"%@,%@,%@",name, phoneNumber, address);
}
//写入plist文件
NSMutableArray *myArray = [NSMutableArray array];
NSDictionary *dict1 = @{
@"name":@"赵六",
@"address":@"北京" };
NSDictionary *dict2 = @{
@"name":@"钱七",
@"address":@"上海"
};
[myArray addObject: dict1];
[myArray addObject: dict2];
[myArray writeToFile:@"/users/tarena/desktop/aaa.plist" atomically:YES];
复制代码