您的位置:首页 > 移动开发 > IOS开发

IOS 数据存储

2014-06-07 22:47 253 查看
IOS中数据存储一般分为以下几种方式

1、XML属性列表(plist)归档
2、preference(偏好设置)
3、NSKeyedArchiver归档(NSCoding)
4、SQLite3
5、Core Data
鄙人才疏,先扯扯前三种刚学的存储方式,做个总结以备复习使用

1、首先了解沙盒的概念,他是应用的系统文件夹,每个应用的沙盒是相互独立的,不能彼此访问(IOS8打破了这一惯例)。谈到数据存储,就不得交代下数据存储在哪里,一般是存储在沙盒的几个文件中:

Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录

接下来尝试将数据存储在documents中,获取Documents目录有这么两个方法:

1、NSString *home = NSHomeDirectory();

2、NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

方法1获取到了应用程序沙盒目录,进一步需要使用stringByAppendingString方法拼接出Documents的最终路径,这怎么说也有点繁琐。苹果给咱提供了第二种比较牛逼的方法,获取到的是一个Array对象,其实里面就一个文件夹,随意lastObject或firstObject都能靠谱的拿到,拼接个要存储到的文件名,直接write进去,直接看小弟的代码:

NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 拼接文件路径
NSString *path = [doc stringByAppendingPathComponent:@"abc.plist"]
;

NSArray *arr = @[@"luseike", @"25"];
[arr writeToFile:path atomically:YES];


documents中已经出现了abc.plist(啰嗦句,documents里面存的是plist文件,这个你肯定知道,它本质上是XML文件。plist文件中能存储系统自带的一些数据类型,比如NSArray、NSString、NSNumber……,也就是用writeToFile方法的对象)

2、在来试试第二种存储方式吧,preference是专门用来存储应用程序的配置信息的。如果利用系统里的偏好设置来存储数据,默认是存储中Preference文件夹下面的,并且会将所有的数据保存到同一文件中。

它具体的使用方法是利用NSUserDefaults对象,每个应用都有自己的UserDefault,代码如下:

// 获取NSUserDefaults对象
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 保存数据(如果设置数据之后没有同步, 会在将来某一时间点自动将数据保存到Preferences文件夹下面)
[defaults setObject:@"luseike" forKey:@"name"];
[defaults setObject:@"man" forKey:@"gender"];
[defaults setInteger:13 forKey:@"age"];
[defaults setDouble:10.1 forKey:@"height"];


preference下面存储的数据不会立即更新,你可以手动同步下,[defaults synchronize]; 轻松搞定。保存的时候是set进去的,读取的时候当然也要按照这个套路来才行,上代码:

// 1.获取NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 2.通过NSUserDefaults获取保存的数据
NSString *name = [defaults objectForKey:@"name"];
int age = [defaults integerForKey:@"age"];
NSLog(@"%@", name);
NSLog(@"%d", age);


苹果居然给我们提供了逆天的integerForKey,当然还有floatFor、doubleFor……

3、上面这两种方式都只能存储系统自带的数据类型,如果要存我们自定义的数据类型,就有点尴尬了,这就不得不邪恶的搬出第三种方式了

NSKeyedArchiver这哥们牛逼的很,自定义一个Person类,有name、age、height三个属性,来看看NSKeyedArchiver怎么存储

// 1.创建对象
/*
NJPerson *p = [[NJPerson alloc] init];
p.name = @"lnj";
p.age = 28;
p.height = 1.76;
*/

NJStudent *stu = [[NJStudent alloc] init];
stu.name = @"luseike";
stu.age = 25;
stu.height = 1.8;
stu.weight = 60;

// 2.获取文件路径
NSString *docPath =  [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [docPath stringByAppendingPathComponent:@"stu.xxoo"];
NSLog(@"path = %@", path);

// 3.将自定义对象保存到文件中
//    [NSKeyedArchiver archiveRootObject:p toFile:path];
[NSKeyedArchiver archiveRootObject:stu toFile:path];


这么使用,有一个条件,那就是要存储的类型必须实现NSCoding协议里面定义的两个方法,这两个方法描述了如何对数据进行存储

// 当将一个自定义对象保存到文件的时候就会调用该方法
// 在该方法中说明如何存储自定义对象的属性
// 也就说在该方法中说清楚存储自定义对象的哪些属性
- (void)encodeWithCoder:(NSCoder *)encoder
{
NSLog(@"NJPerson encodeWithCoder");
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInteger:self.age forKey:@"age"];
[encoder encodeFloat:self.height forKey:@"heigth"];
}

// 当从文件中读取一个对象的时候就会调用该方法
// 在该方法中说明如何读取保存在文件中的对象
// 也就是说在该方法中说清楚怎么读取文件中的对象
- (id)initWithCoder:(NSCoder *)decoder
{
NSLog(@"NJPerson initWithCoder");
if (self = [super init]) {
self.name = [decoder decodeObjectForKey:@"name"];
self.age = [decoder decodeIntegerForKey:@"age"];
self.height = [decoder decodeFloatForKey:@"heigth"];
}
return self;
}


还有一点需要注意,如果一个类继承了Person类,子类中添加的属性是保存不成功的,子类必须重写协议方法才可以。比如定义了继承Person类的Student类,新增weight属性,Student实现协议的代码如下

- (void)encodeWithCoder:(NSCoder *)aCoder
{
[super encodeWithCoder:aCoder];
NSLog(@"NJStudent encodeWithCoder");
[aCoder encodeFloat:self.weight forKey:@"weight"];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
NSLog(@"NJStudent initWithCoder");
self.weight = [aDecoder decodeFloatForKey:@"weight"];
}
return self;
}


然后像保存Person一样的方式就能正常保存Student了

先嘚瑟这么多,以后学习了新知识再补充,新手学习中,请勿拍砖,待续……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: