iOS 数据持久化

前言


我们老是有一种一年到头来发现自己什么都没有干,一年就这样过去了,今天灌点心灵鸡汤。


目录


一、什么是持久化


二、沙盒是什么


2.1 沙盒简介及获取沙盒路径

2.2 Documents

2.2 Library

2.2.1 Caches

2.2.2 Preferences

2.3 SystemData

2.4 tmp


三、数据持久化的几种方式


3.1 property list(属性列表)

3.2 Preference(偏好设置)

3.3 NSKeyedArchiver(归档)

3.4 SQLite3/FMDB(嵌入式数据库)

3.5 CoreData(面向对象的嵌入式数据库)


~ 注意:SQLite3/FMDB以及CoreData要说的东西很多将在下章继续


一、什么是持久化


所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据。


二、沙盒是什么


2.1 沙盒简介及获取沙盒路径


沙盒(sandbox):每一个App都有一个存储空间。iOS系统为每个应用程序创建自己的目录,每个应用程序只能访问自己的目录,不能相互通信。


简单粗俗一点来说:沙盒就是存储app所有的数据的路径,且默认情况下只能访问程序自己的目录


iOS沙盒主要包括下面几个文件:

iOS 数据持久化

获取沙盒目录路径


    NSLog(@"%@",NSHomeDirectory());


iOS 数据持久化


注意: 每次编译运行都会生成一个新的沙盒路径,而真机不会生成新的沙盒。


2.2 Documents


保存持久化数据,会备份。一般用来存储需要持久化的数据。


一般我们在项目中,我们会吧一些用户的登录信息进行存储,以及搜索历史记录等等一些关键数据。


   //获取Documents目录路径

    NSString *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];


iOS 数据持久化


2.2 Library


Library里面包含两个文件夹(Caches和Preferences)


2.2.1 Caches


缓存,iTunes不会备份该目录。内存不足时会被清除,应用没有运行时,可能会被清除,。一般存储体积大、不需要备份的非重要数据。


2.2.2 Preferences


保存持久化数据,会备份NSUserDefaults默认存放在此文件夹


2.3 SystemData


SystemData:去年还是没有这个文件夹的,今天写这篇文章时打开沙盒一看,发现居然多了SystemData这个文件夹,刚开始以为只有这个才有,然后查看好几个别的沙盒路径,发现都多了一个SystemData文件夹。于是乎各种百度,发现网上没有这个的细聊,几乎都是这样的话语,要么就是没有提到这玩意。


iOS 数据持久化


到最后始终没有找到我想要的答案。于是凭着自己的理解和开发经验对此进行琢磨和渗透。


字眼的意思是存放系统的一些数据,从NSCachesDirectory和NSDocumentDirectory试探猜测是否存在一个NSSystem...开头。从NSCachesDirectory进入头文件去查找相关的例如NSSystem...开头的并没有 。


iOS 数据持久化


iOS 数据持久化



能怎么办,各种百度*都没有找到该东西的解释,最后去官方文献中各种翻资料,仍旧是一所所获。。最后结论可能是这东西可能不是很重要吧。。


2.4 tmp


临时文件夹


iTunes不会备份这个目录,用来保存临时数据,应用退出时会清除该目录下的数据。


// 获取tmp目录路径

NSString *tmp = NSTemporaryDirectory();


一般开发者需要临时保存的数据但不需要长期保留使用可以放到此文件夹


三、数据存储的几种方式


3.1 property list(属性列表)


只能存储系统自带的数据类型,一般实际开发中存储字典、数组,自定义的模型无法进行存储


#define kUserPath [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"latestQuery.plist"]


- (IBAction)plistSaveOnClick:(id)sender {

   

    //    NSMutableDictionary *dic = [NSMutableDictionary dictionary];

    //    [dic setObject:@"小明" forKey:@"name"];

    //    //将字典持久化到Documents/

    //    [dic writeToFile:path atomically:YES];

    NSArray *arr = @[@"123",@"咋啦"];

    /**

     1、获取应用的文件夹(应用沙盒)

     NSSearchPathDirectory 搜索的目录

     NSSearchPathDomainMask 搜索范围 NSUserDomainMask:表示在用户的手机上查找

     expandTilde 是否展开全路径~ 如果没有展开,应用的沙盒路径就是~

     存储一定要展开路径 如果要存东西 必须要是YES

     */

    //YES:///Users/huahua/Library/Developer/CoreSimulator/Devices/0FB528AF-C34D-4F64-A723-6129E3FF3964/data/Containers/Data/Application/6FEDA2B8-40C2-40EA-9685-FE6DC828D7D2/Library/Caches

    //NO: ~/Library/Caches

    self.saveLabel.text = [NSString stringWithFormat:@"%@",arr];

    [arr writeToFile:kUserPath atomically:YES]; 

}

- (IBAction)plistReadOnClick:(id)sender {

   NSArray *arr =  [NSArray arrayWithContentsOfFile:kUserPath];    

    self.readLabel.text = [NSString stringWithFormat:@"%@ ",arr];

    NSLog(@"%@",arr);

}


3.2 Preference(偏好设置)


只能存储系统自带的数据类型,自定义的对象无法存储


NSUserDefaults就是默认存放在此文件夹下面,如下案例代码


/**

偏好设置好处:

1.不需要关心文件名(不需要设置路径)

2.键值对存储(账号相关信息) 对象存储

底层实现原理就是封装了一个字典

*/

- (IBAction)userDefaultsSaveOnClick:(id)sender {

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

    //放到缓存里,并不会马上放到文件里面

    [userDefaults setObject:@"123" forKey:@"account"]; //对象

    [userDefaults setObject:@"123456" forKey:@"pwd"];

    //BOOL类型

    [userDefaults setBool:YES forKey:@"status"];

    //在ios7 默认不会马上跟硬盘同步  同步操作 起到立即存储的作用

    [userDefaults synchronize];

    self.saveLabel.text = [NSString stringWithFormat:@"account:%@ pwd:%@",[[NSUserDefaults standardUserDefaults]objectForKey:@"account"],[[NSUserDefaults standardUserDefaults]objectForKey:@"pwd"]];

}

- (IBAction)userDefaultsReadOnClick:(id)sender {


    NSString *account = [[NSUserDefaults standardUserDefaults]objectForKey:@"account"];

    NSString *pwd = [[NSUserDefaults standardUserDefaults]objectForKey:@"pwd"];

    NSLog(@"偏好设置---账号:%@ 密码:%@",account,pwd);

    self.readLabel.text = [NSString stringWithFormat:@"account:%@ pwd:%@",account,pwd];

}

- (IBAction)clearOnClick:(id)sender {

    NSUserDefaults *userDefalits = [NSUserDefaults standardUserDefaults];

    [userDefalits removeObjectForKey:@"account"];

    [userDefalits removeObjectForKey:@"pwd"];

    [userDefalits synchronize];

}


3.3 NSKeyedArchiver(归档)


可以存储自定义的数据类型,这里就不适用runtime实现了,如果想要采用runtime实现,可查看此篇笔者写的此篇文章玩转runtime的前世今生看我足矣


/************UserManager.h****************/

@interface UserManager : NSObject<NSCoding>

@property (nonatomic, assign) int ID;

@property(nonatomic,copy)NSString *account;

@property(nonatomic,copy)NSString *pwd;

@property(nonatomic,assign)int age;


//自定义的归档保存数据的方法

+(void)saveUser:(UserManager *)user;


//自定义的读取沙盒中解档出的数据

+(UserManager *)getUser;


/************UserManager.m****************/

#import "UserManager.h"

@implementation UserManager

/** 什么时候调用:自定义对象归档的时候

 作用:用来描述当前对象里面的哪些属性要归档

 aCoder:用来归档

 */

- (void)encodeWithCoder:(NSCoder *)aCoder{

  [aCoder encodeObject:_account forKey:@"account"];

  [aCoder encodeInteger:_age forKey:@"age"];   

}

/** 什么时候调用:解档对象的时候调用

 作用:用来描述当前对象里面的哪些属性要解档*/

- (instancetype)initWithCoder:(NSCoder *)coder{

    if (self  = [super init]) {

        //注意一定要给成员变量赋值保存起来

 _account = [aDecoder decodeObjectForKey:@"account"];

      _age =   [aDecoder decodeIntForKey:@"age"];

    return self;

}


//自定义的归档保存数据的方法

+(void)saveUser:(UserManager *)user{

NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;

    NSString *path=[docPath stringByAppendingPathComponent:@"UserInfo.plist"];

    [NSKeyedArchiver archiveRootObject:user toFile:path];

}


//自定义的读取沙盒中解档出的数据

+(UserManager *)getUser{

NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;

    NSString *path=[docPath stringByAppendingPathComponent:@"UserInfo.plist"];

    UserManager *user = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

    return user;


}

@end


/************ViewController.m****************/

#pragma mark - NSKeyedArchiver(归档)

/** 自定义对象想要归档,则自定义对象必须遵守NSCoding协议,实现协议方法 */

- (IBAction)keyedArchiverSaveOnClick:(id)sender {

    

    UserManager *userInfo = [[UserManager alloc]init];

    userInfo.account = @"18673556376";

    userInfo.age = 15;

     [UserManager saveUser:userInfo];

    self.saveLabel.text = [NSString stringWithFormat:@"%@ %zd",userInfo.account,userInfo.age];

}

- (IBAction)keyedArchiverReadOnClick:(id)sender {

    UserManager *userInfo = [UserManager getUser];

    NSLog(@"NSKeyedArchiver归档-----账号:%@---年龄:%d",userInfo.account,userInfo.age);

    self.readLabel.text = [NSString stringWithFormat:@"%@ %zd",userInfo.account,userInfo.age];

}


君凯商联网-iOS-字唐名僧