iOS中几种数据持久化方案

概念

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

方案

  • plist文件(属性列表)
    将某些特定的类,通过XML文件的方式保存在目录中。

    1. 获得文件路径

       NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
       NSString *fileName = [path stringByAppendingPathComponent:@"myplist.plist"];
      
    2. 存储

       NSArray *array = @[@"123", @"456", @"789"];
       [array writeToFile:fileName atomically:YES];
      
    3. 读取

       NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
       NSLog(@"%@", result);
      
  • preference(偏好设置)

    1. 获得NSUserDefaults文件

       NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
      
    2. 向文件中写入内容

       [userDefaults setObject:@"myString" forKey:@"string"];
       [userDefaults setBool:YES forKey:@"bool"];
       [userDefaults setInteger:21 forKey:@"integer"];
      
    3. 立即同步

       [userDefaults synchronize];
      
    4. 读取文件

       NSString *name = [userDefaults objectForKey:@"string"];
       BOOL sex = [userDefaults boolForKey:@"bool"];
       NSInteger age = [userDefaults integerForKey:@"integer"];
      
  • NSKeyedArchiver(归档)

    1. 属性设置

       @interface Person : NSObject //2.设置属性
       @property (strong, nonatomic) UIImage *avatar;
       @property (copy, nonatomic) NSString *name;
       @property (assign, nonatomic) NSInteger age;
       @end
      

    2.实现协议方法

    NSCoding协议声明了两个方法,这两个方法都是必须实现的。一个用来说明如何将对象编码到归档中,另一个说明如何进行解档来获取一个新对象。

      //解档
      - (id)initWithCoder:(NSCoder *)aDecoder {
      	if ([super init]) {
      	self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
      	self.name = [aDecoder decodeObjectForKey:@"name"];
      	self.age = [aDecoder decodeIntegerForKey:@"age"];
      	}
      	return self;
      }
      //归档
      - (void)encodeWithCoder:(NSCoder *)aCoder {
      	[aCoder encodeObject:self.avatar forKey:@"avatar"];
      	[aCoder encodeObject:self.name forKey:@"name"];
      	[aCoder encodeInteger:self.age forKey:@"age"];
      }
    

    如果需要归档的类是某个自定义类的子类时,就需要在归档和解档之前先实现父类的归档和解档方法。即 [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法;

    3.使用

    需要把对象归档是调用NSKeyedArchiver的工厂方法 archiveRootObject: toFile: 方法。

      NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
      Person *person = [[Person alloc] init];
      person.avatar = self.avatarView.image;
      person.name = self.nameField.text;
      person.age = [self.ageField.text integerValue];
      [NSKeyedArchiver archiveRootObject:person toFile:file];
    

    需要从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile: 即可。

      NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
      Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
      if (person) {
      	self.avatarView.image = person.avatar;
      	self.nameField.text = person.name;
      	self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
      }
    
  • SQLite3
    SQLite3的使用还是比较麻烦,在一般开发过程中,使用的都是第三方开源库 FMDB

    1. 打开数据库

       NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.db"];
       FMDatabase *database = [FMDatabase databaseWithPath:path];
       if (![database open]) {
       NSLog(@"数据库打开失败!");
       }
      
    2. 更新

       //常用方法有以下3种:
       - (BOOL)executeUpdate:(NSString*)sql, ...
       - (BOOL)executeUpdateWithFormat:(NSString*)format, ...
       - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
       //示例
       [database executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"];
       //或者
       [database executeUpdate:@"INSERT INTO t_person(name, age) VALUES(?, ?)", @"Bourne", [NSNumber numberWithInt:42]];
      
    3. 查询

       查询方法有3种
       - (FMResultSet *)executeQuery:(NSString*)sql, ...
       - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
       - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
       查询示例
       //1.执行查询
       FMResultSet *result = [database executeQuery:@"SELECT * FROM t_person"];
       //2.遍历结果集
       while ([result next]) {
       	NSString *name = [result stringForColumn:@"name"];
       	int age = [result intForColumn:@"age"];
       }
      
    4. 线程安全

      • 创建队列

          FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
        
      • 使用队列

          [queue inDatabase:^(FMDatabase *database) {
          	[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_1", [NSNumber numberWithInt:1]];
          	[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_2", [NSNumber numberWithInt:2]];
          	[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_3", [NSNumber numberWithInt:3]];
          	FMResultSet *result = [database executeQuery:@"select * from t_person"];
          	while([result next]) {
          	}
          }];
        
  • CoreData

    1. 创建项目的时候选择使用Core Data,项目创建成功后,会在AppDelegate类中自动添加相关代码,此外,还会自动生成一个数据模型文件。如果项目在创建的时候没有选择使用Core Data,但是在后面需要使用,那么需要手动的添加AppDelegate中的相关代码。此外还需要手动添加一个Data Model文件。
      在创建Data Model文件时需要注意文件名要与AppDelegate.m中managedObjectModel方法中提到的文件名称相匹配。

    2. 有了Data Model文件后,就可以在里面添加实体和关系,实际上就是向数据库中添加表格和建立表格之间的关联。

    3. 创建好实体后,可以通过添加NSManagedObject subclass文件,系统可以自动添加实体对应的数据模型类。

    4. 通过代码实现数据库的操作

      • 插入数据

          -(void)insert {       
           AppDelegate *delegate = [[UIApplication sharedApplication] delegate];        
          //1. 获得context    
          NSManagedObjectContext *context = delegate.managedObjectContext;    
          //2. 找到实体结构,并生成一个实体对象   
           /*     NSEntityDescription实体描述,也就是表的结构     参数1:表名字     参数2:实例化的对象由谁来管理,就是context     */   
            NSManagedObject *stu = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:context];  
            NSManagedObject *class1 = [NSEntityDescription insertNewObjectForEntityForName:@"Classes" inManagedObjectContext:context];    
            [class1 setValue:[NSNumber numberWithInt:1] forKey:@"c_id"];    
            [class1 setValue:@"一班" forKey:@"c_name"];        
            //3. 设置实体属性值    
            [stu setValue:[NSNumber numberWithInt:1] forKey:@"s_id"];    
            [stu setValue:@"jerehedu" forKey:@"s_name"];    
            [stu setValue:class1 forKey:@"s_class"];        
            //4. 调用context,保存实体,如果没有成功,返回错误信息    
            NSError *error;    
            if ([context save:&error]){        
            	NSLog(@"save ok");    
            } else{        
            	NSLog(@"%@",error);   
            }}
        
      • 查询全部数据

          -(void)selectAll {    
          AppDelegate *delegate = [[UIApplication sharedApplication] delegate]; 
          NSManagedObjectContext *context = delegate.managedObjectContext;        
          NSEntityDescription *stu = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:context];        
          //构造查询对象    
          NSFetchRequest *request = [[NSFetchRequest alloc] init];    
          [request setEntity:stu];        
          //执行查询,返回结果集    
          NSArray *resultAry = [context executeFetchRequest:request error:nil];        
          //遍历结果集    
          for (NSManagedObject *enity in resultAry) {        
          	NSLog(@"id=%i name=%@ class=%@",[[enity valueForKey:@"s_id"] intValue],[enity valueForKey:@"s_name"],[[enity valueForKey:@"s_class"] valueForKey:@"c_name"]);    
          }}
        
      • 查询指定数据

          - (void)selectAll {    
          		AppDelegate *delegate = [[UIApplication sharedApplication] delegate];        
          		NSManagedObjectContext *context = delegate.managedObjectContext;        
          		NSEntityDescription *stu = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:context];        
          		//构造查询对象    
          		NSFetchRequest *request = [[NSFetchRequest alloc] init];    
          		[request setEntity:stu];        
          		//执行查询,返回结果集    
          		NSArray *resultAry = [context executeFetchRequest:request error:nil];        
          		//遍历结果集    
          		for (NSManagedObject *enity in resultAry) {        
          			NSLog(@"id=%i name=%@ class=%@",[[enity valueForKey:@"s_id"] intValue],[enity valueForKey:@"s_name"],[[enity valueForKey:@"s_class"] valueForKey:@"c_name"]);    
          		}}
        
      • 删除指定数据

          - (void)delete{    
          	//删除 先找到,然后删除    
          	AppDelegate *delegate = [[UIApplication sharedApplication] delegate];    
          	NSManagedObjectContext *context = delegate.managedObjectContext;        
          	NSEntityDescription *stu = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:context];        
          	NSFetchRequest *request = [NSFetchRequest new];    
          	[request setEntity:stu];        
          	//构造查询条件,相当于where子句    
          	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"s_id=%i",1];        
          	//把查询条件放进去    
          	[request setPredicate:predicate];    
          	//执行查询    
          	NSManagedObject *obj = [[context executeFetchRequest:request error:nil] lastObject];    
          	//删除    
          	if (obj) {        
          		[context deleteObject:obj];        [context save:nil];    
          		}        
          		[self selectAll];
          		}
        
posted @ 2016-11-28 10:38  AliliWl  阅读(230)  评论(0编辑  收藏  举报