介绍
概述
无论是IOS应用或者是其它的网页应用,都有数据存储。在IOS中,数据存储的方式主要有五种。这五种方式各自有着各自的特点,使用的时候我们需要分清具体情况然后选择最合适的存储方式。这五种方式分别是:
- XML属性列表(plist)
- Preference(偏好设置)
- NSKeyedArchiver归档(NSCoding)
- SQLite3
- Core Data
对于沙盒的介绍Scandbox
每个ios应用都有自己的沙盒(所谓的沙盒就是应用的文件系统),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问本应用的沙盒。
应用沙盒的文件系统目录,如下图所示:
它里面的内容具体包括:
- 应用程序包
- Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。
- temp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
- Library/Caches:保存应用运行时生成的需要持久化的数据,iTUnes同步设备时不会备份该目录。一般存储体积大,不需要备份的非重要数据
- Library/Preference:保存应用的所有偏好设置,ios的Settings(设置)应用汇在该目录中查找应用的设置消息。iTunes同步设备时会备份该目录。
应用沙盒目录的常见获取方式:
- 沙盒根目录:NSString *home = NSHomeDirectory();
- Documents:(2种方式):
1.利用沙盒根目录直接拼接“Documents”字符串
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];
不建议采用上面的方法,因为新版本的操作系统可能会修改目录名。
2.利用NSSearchPathForDirectoriesInDomans函数
NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSUserDomanMask:代表从用户文件夹下找
YES:代表展开路径中的波浪字符‘~’
在ios中,只有一个目录跟传入的参数匹配,所以这个集合里面只有一个元素。
- temp目录:NSString *temp = NSTemporaryDirectory();
- Library/Caches:跟Documents类似的两种方法
1.利用沙盒根目录拼接“Caches”字符串
2.利用NSSearchPathForDirectoriesInDomains函数(将函数的第2个参数改为:NSCachesDirectory即可)
- Library/Preference:通过NSUserDefaults类存取该目录下的设置信息。
一、属性列表存储
属性列表是一种XML格式的文件,其扩展名为plist;如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等烈性,就可以使用writeToFile:automically:方法直接将对象写到属性列表文件中。
eg:把一个NSDictionary写入plist文件并读取:
- (void)saveDictToDocuments
{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/animal.plist",documentPath];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"ZhuBaJie" forKey:@"name"];
[dict setObject:@"27" forKey:@"age"];
[dict setObject:@"gao lao zhuang" forKey:@"address"];
if([dict writeToFile:path atomically:YES])
{
NSLog(@"写入数据成功");
}
}
- (void)readDictFormDocuments
{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/animal.plist",documentPath];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"%@",dict);
}
运行结果:
2016-03-10 18:14:15.557 SandboxTest[7069:2123397] {
address = "gao lao zhuang";
age = 27;
name = ZhuBaJie;
}
二、偏好设置
很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能。每个应用都有个NSUserDefaults实例,通过它来存取偏好设置。比如,保存用户名、字体大小、是否自动登录
注意事项:使用NSUserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓冲中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题可以通过调用syncharonize方法强制写入。[[NSUserDefaults standardUserDefaults] synchronize];
三、NSKeyedArchiver
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以直接使用NSKeyedArchiver进行归档和恢复。
不是所有的对象都可以直接用这种方法机型归档,只有遵循了NSCoding协议的对象才可以。
NSCoding协议有两个方法:
- encodeWithCoder:
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量。 - initWithCoder:
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。
eg:把array归档存储和读取
- (void)saveArrayToDocuments
{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/array.archive",documentPath];
NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c", nil];
if ([NSKeyedArchiver archiveRootObject:array toFile:path]) {
NSLog(@"数据写入成功");
}
}
- (void)readArrayFromDocuments
{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/array.archive",documentPath];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@",array);
}
运行结果:
2016-03-10 18:39:03.780 SandboxTest[7093:2128040] (
a,
b,
c
)
eg:把Person对象归档存储和读取
- (void)savePersonObjToArchive
{
NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/person.archive",document];
Person *person = [[Person alloc] init];
person.name = @"JonQi";
person.age = 20;
person.height = 1.80f;
if ([NSKeyedArchiver archiveRootObject:person toFile:path]) {
NSLog(@"对象保存成功");
}
}
- (void)readPersonObjFromArchive
{
NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/person.archive",document];
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"Person object:name=%@,age=%d,height=%f",person.name,person.age,person.height);
}
运行结果:
2016-03-10 21:23:51.968 ScandboxTest[3424:39823] Person object:name=JonQi,age=20,height=1.800000
使用NSKeyedArchiver进行归档对象时请注意:
- 如果父类也遵守了NSCoding协议,应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码,即也能被归档;应该在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码,即也能被恢复。
- 使用archiveRootObject:toFile:方法可以将一个对象直接写入到一个文件中,但有时候可能将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象。
NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取文件内容。可以使用[NSMutableData data]创建可变数据空间。如图
eg:利用NSData存储多个对象到同一个文件中以及读取多个对象:
- (void)savePersonObjToArchive
{
NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/person.archive",document];
Person *person1 = [[Person alloc] init];
person1.name = @"JonQi";
person1.age = 20;
person1.height = 1.80f;
Person *person2 = [[Person alloc] init];
person2.name = @"XiaoM";
person2.age = 10;
person2.height = 1.60f;
// 创建一块可变数据区
NSMutableData *mutableData = [NSMutableData data];
// 将数据区连接到一个NSKeyedARchiver对象
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mutableData];
// 开始存档对象,存档的数据都会存储到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存档完毕,一定要调用的方法
[archiver finishEncoding];
[mutableData writeToFile:path atomically:YES];
}
- (void)readPersonObjFromArchive
{
NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/person.archive",document];
NSData *data = [NSData dataWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"];
[unarchiver finishDecoding];
NSLog(@"person1 object:name=%@,age=%d,height=%f",person1.name,person1.age,person1.height);
NSLog(@"person2 object:name=%@,age=%d,height=%f",person2.name,person2.age,person2.height);
}
运行结果:
2016-03-10 21:46:57.285 ScandboxTest[4907:60533] person1 object:name=JonQi,age=20,height=1.800000
2016-03-10 21:46:57.285 ScandboxTest[4907:60533] person2 object:name=XiaoM,age=10,height=1.600000
利用归档实现深复制:
467

被折叠的 条评论
为什么被折叠?



