IOS应用中的数据存储

来源:互联网 发布:联想笔记本网络驱动 编辑:程序博客网 时间:2024/05/01 02:44

介绍

概述

无论是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协议有两个方法:

  1. encodeWithCoder:
    每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量。
  2. 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.8000002016-03-10 21:46:57.285 ScandboxTest[4907:60533] person2 object:name=XiaoM,age=10,height=1.600000

利用归档实现深复制:
这里写图片描述

0 0