IOS 数据存储

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了

先嘚瑟这么多,以后学习了新知识再补充,新手学习中,请勿拍砖,待续……

原文地址:https://www.cnblogs.com/luseike/p/3775486.html