【理解】iOS数据持久化存储

总述:

所谓数据持久化是指,将数据存储下来,使得应用程序下次打开或者机器重启后可以继续访问之前保存的数据。iOS开发中有多种持久化方案,如:

  • plist文件(属性列表)
  • NSKeyedArchiver(对象归档)
  • preference(偏好设置)
  • sqlite3
  • coredata 
    沙盒机制:ios不同应用有独立的文件目录,不能互相访问。这个独立的文件目录就称为”沙盒”. 
    1、目录结构,苹果帮忙创建应用的目录机构,如下:
  • “应用程序包”
  • Documents 保存的持久性最强,可同步到其它地方。
  • Library 下有Cache 和Preferences
  • tmp:用于存放临时文件, 
    2、目录说明 
    “应用程序包”:这里存放的是应用程序源文件,包括资源文件和可执行文件。
                       NSString *path = [NSBundle mainBundle]bundlePath];
           “Documents”:最常用的目录,itunes同步该应用时,会同步此文件中的内容,适合存储重要数据。
                        NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject;

             Library /Cache:ITunes不会同步此文件夹,适合存储体积大,不需要备份的非重要数据。

                       NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,yes).firstObject;

             Library /Preferences::ITunes会同步此文件夹,通常保存应用的设置信息

            tmp:iTunes不会同步此文件夹,系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存一些临时文件,用完就删除。

                       NSString *path= NSTemporaryDirectory();


一、plist 属性文件

plist文件是将某些特定的类,通过xml文件的方式保存在目录中。 
可以被序列化的类型: 
1. NSArray 
2. NSMutableArray 
3. NSDictionary 
4. NSMutableDictionary 
5. NSData 
6. NSMutableData 
7. NSString 
8. NSMutableString 
9. NSNumber 
10. NSDate 
只有以上10种类型才能使用plist文件存储。存储时使用writeToFile:atomically:方法。其中第二个参数atomically表示是否需要先写入一个辅助文件,再把辅助文件拷贝到目标文件地址。这是更安全的卸乳文件方法,一般都用yes。 
读取时使用 arrayWithContentsOfFile:方法。

1、获取路径 
NSString *path = 
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; 
NSString *fileName = [path 
stringByAppendingPathComponet:@”test.plist”]; 
2、存储数据 
NSString *array=@[@”中”,@”4g”,@”3g”]; 
[array writeToFile:fileName atomically:YES]; 
3、读取数据 
NSArray *data =[NSArray arrayWithContentsofFIle:fileName];


二、preference 偏好设置

// 偏好设置

-(void)persistencePreferences{

//    1、获取NSUserDefaults文件

    NSUserDefaults *userDefaultS = [NSUserDefaults standardUserDefaults];

//    2、向文件写入文件内容

    [userDefaultS setInteger:50 forKey:@"age"];

    [userDefaultS setObject:@"zhangsan" forKey:@"name"];

    [userDefaultS setBool:YES forKey:@"sex"];

    [userDefaultS synchronize];

//    读取内容

    NSString *name = [userDefaultS stringForKey:@"name"];

    NSInteger age = [userDefaultS integerForKey:@"age"];

    BOOL sex = [userDefaultS boolForKey:@"sex"];

}

偏好设置通常用来保存应用程序的配置信息,一般不要在偏好设置中保存其它数据。

调用synchronize方法就会立即写入文件,如果没有调用,系统会根据 I/O情况不定时刻保存到文件中。

偏好设置会将所有数据保存到preference目录下的一个以此应用报名来命名的plist文件。

存储自定义对象需要实现NSCoding协议



三、NSKeyedArchiver归解档

归解档操作(NSKeyedArchiver/NSKeyedUnArchiver)通过对自定义对象进行操作。归解档后的自定义对象很方面进行持久化操作,方便于对象以文件的形式进行存储。归解档的对象需要实现NSCoding协议。

1、自定义对象实现NSCoding协议

@interface UserModel : NSObject<NSCoding>

[objc]  view plain  copy
 
  1. @property(nonatomic,copy)NSString *name;  
  2. @property(nonatomic,assign)NSInteger age;  
  3. @property(nonatomic,assign)BOOL sex;  
  4.   
  5. @end  

[objc]  view plain  copy
 
  1. #import "UserModel.h"  
  2.   
  3. @implementation UserModel  
  4.   
  5. //归档  
  6. -(void)encodeWithCoder:(NSCoder *)aCoder{  
  7.       
  8.     [aCoder encodeObject:self.name forKey:@"name"];  
  9.     [aCoder encodeInteger:self.age forKey:@"age"];  
  10.     [aCoder encodeBool:self.sex forKey:@"sex"];  
  11.       
  12. }  
  13. //解档  
  14. - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{  
  15.   
  16.     if([self init]){  
  17.       
  18.         self.name = [aDecoder decodeObjectForKey:@"name"];  
  19.         self.age = [aDecoder decodeIntegerForKey:@"age"];  
  20.         self.sex = [aDecoder decodeBoolForKey:@"sex"];  
  21.     }  
  22.     return  self;  
  23. }  

2、使用NSKeyedArchiver进行对象归档

[objc]  view plain  copy
 
  1. - (void)persistArchived{  
  2.     NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;  
  3.     NSString *filePath = [path stringByAppendingPathComponent:@"user.data"];  
  4.     UserModel *user =[[UserModel alloc]init];  
  5.     user.name = @"zhangsan";  
  6.     user.age50;  
  7.     user.sex = NO;  
  8.     //调用NSKeyedArchiver 工厂方法实现归档:  
  9.     [NSKeyedArchiver archiveRootObject:user toFile:filePath];  
  10.    //解档:从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile:。  
  11.     UserModel *unarchiverUser = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];  
  12.       
  13.     NSLog(@"unarchiverUser-name%@,unarchiverUser-name%d, unarchiverUser-age%ld", unarchiverUser.name, unarchiverUser.sex, unarchiverUser.age);  
  14. }  
如果需要归档的类是某个自定义类的子类时,就需要在归档和解档之前先实现父类的归档和解档方法。  [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法;

建议对象也同时实现NSCopying协议,该协议允许复制对象,要实现NSCopying协议须实现 -(id)copyWithZone:(NSZone *)zone 方法 。

保存的文件的扩展名可以任意指定。


四、sqlite3

1、概述

sqlite是个开源嵌入式关系数据库,SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程.sqlite不是覆盖存储,不像其他持久化操作,需要把整个文件读取出来,然后修改数据后把整个内容写入文件,所以他们都不适合存储大量数据。

.字段类型
    表面上SQLite将数据分为以下几种类型:

    integer:整数

    real:实数(浮点数)

    text:文本字符串

    blob:二进制数据,比如文件,图片之类的。
  sqlite数据类型,只是一种数据类型的规范,实际上是无类型的,不指定数据类型依旧可以存储数据,创建表时也可以不用指定类型,不管为了规范都建议设置正确的数据类型,主键的话必须设置为integer类型。

2、操作数据库

1、打开数据库指定数据库文件,指定或者创建一张表

[objc]  view plain  copy
 
  1. -(void)openDatabase{  
  2. //   1.设置文件名  
  3. NSString *dbFile = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)firstObject stringByAppendingPathComponet:@"user.db"]; 
  4. //2.打开数据库文件
  5. NSString *dbFile = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"user.db"];  

2.打开数据库文件,如果没有就会自己创建一个表

[objc]  view plain  copy
 
  1. NSInteger result = sqlite3_open(dbFile.UTF8String,&sqlite); 
  2. if(result = SQLITE_OK){
  3. NSLog(@"打开成功"); 

  4. char &error = NULL
  5. sqlite3_exec(sqlite,"CREATE TABLE IF NOT EXISTS t_user(id integer primary key autoincrement,name text ,age integer)",NULL,NULL,&error);
  6. if(error){ 
  7. NSLog(@"create error %S",error);
  8. }
  9. }else {
  10. NSLog("打开失败");
  11. }
  12. }

3、执行指令   使用sqlite_exec()方法执行除查询以外的其他数据库操作
如插入数据:

[objc]  view plain  copy
 
  1. -(void)insertData{ 
  2. NSString *name=@"zhangsan";
  3. NSInteger age = 19;
  4. <span style="font-family: 'Helvetica Neue', Helvetica, STheiti, 微软雅黑, 黑体, Arial, Tahoma, sans-serif, serif; line-height: 25.2px;">     NSString *sql=[NSString stringWithFormat:@"INSERT INTO t_user (name,age) VALUES('%@',"%ld"),name,age";</span> 
  5. <span style="font-family: 'Helvetica Neue', Helvetica, STheiti, 微软雅黑, 黑体, Arial, Tahoma, sans-serif, serif; line-height: 25.2px;"char  *error  =NULL sqlite_exec(sqlite,sql.UTF8String,NULL,NULL,&error);</span>
  6. <span style="font-family: 'Helvetica Neue', Helvetica, STheiti, 微软雅黑, 黑体, Arial, Tahoma, sans-serif, serif; line-height: 25.2px;">if (error){</span>
  7. <span style="font-family: 'Helvetica Neue', Helvetica, STheiti, 微软雅黑, 黑体, Arial, Tahoma, sans-serif, serif; line-height: 25.2px;">   NSLog(@"erorr");</span>
  8. <span style="font-family: 'Helvetica Neue', Helvetica, STheiti, 微软雅黑, 黑体, Arial, Tahoma, sans-serif, serif; line-height: 25.2px;">}</span>
  9. }
  10. }

查询指令:

查询需要几条语句配合使用sqlite3_prepare_v2检查sql合法性,sqlite3_step()逐行获取查询结果,不断重复,知道最后一条记录

sqlite3_colum_xxx();获取对应字段类容,参数0,smtp,参数1 代表sql语句中字段的顺序。sqlite3_finalize()释放stmt

例:从表中读取数据到数组中:

[objc]  view plain  copy
 
  1. -(void)selectData{
  2. NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1000];
  3. charchar *sql = "select name,age from t_user;";
  4. sqlite3_stmt *stmt;
  5. NSInteger result = sqlite3_prepare_v2(sqlite,sql,-1,&stmt,NULL);
  6. if(result =SQLITE_OK){
  7. while(sqlite3_step(stmt)==SQLITE_ROW){
  8. charchar *name = sqlite3_column_int(stmt,1); 
  9. Person *person = [Person personWithName:[NSString stringWithUTF8String:name]Age:age];
  10. [mArray addObject:person];
  11. }
  12. sqlite3_finalize(stmt);
  13. }
  14. }

总的来说在操作sqlite来说,这种方法比较麻烦都是c语言的一些函数的调用,可以通过第三方开源api进行调用,这样比较方便,也可以使用系统提供的Core Data ,第三方的话推荐使用fmdb来操作数据库。

你可能感兴趣的:(ios,持久化,sqlite3,plist,沙盒)