iOS中几种数据持久化方案
概念
所谓持久化就是将数据保存到硬盘中,使得应用重启或者机器重启后可以继续访问之前保存的数据。
方案
-
plist文件(属性列表)
将某些特定的类,通过XML文件的方式保存在目录中。-
获得文件路径
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; NSString *fileName = [path stringByAppendingPathComponent:@"myplist.plist"];
-
存储
NSArray *array = @[@"123", @"456", @"789"]; [array writeToFile:fileName atomically:YES];
-
读取
NSArray *result = [NSArray arrayWithContentsOfFile:fileName]; NSLog(@"%@", result);
-
-
preference(偏好设置)
-
获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
-
向文件中写入内容
[userDefaults setObject:@"myString" forKey:@"string"]; [userDefaults setBool:YES forKey:@"bool"]; [userDefaults setInteger:21 forKey:@"integer"];
-
立即同步
[userDefaults synchronize];
-
读取文件
NSString *name = [userDefaults objectForKey:@"string"]; BOOL sex = [userDefaults boolForKey:@"bool"]; NSInteger age = [userDefaults integerForKey:@"integer"];
-
-
NSKeyedArchiver(归档)
-
属性设置
@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-
打开数据库
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.db"]; FMDatabase *database = [FMDatabase databaseWithPath:path]; if (![database open]) { NSLog(@"数据库打开失败!"); }
-
更新
//常用方法有以下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种 - (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"]; }
-
线程安全
-
创建队列
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
-
创建项目的时候选择使用Core Data,项目创建成功后,会在AppDelegate类中自动添加相关代码,此外,还会自动生成一个数据模型文件。如果项目在创建的时候没有选择使用Core Data,但是在后面需要使用,那么需要手动的添加AppDelegate中的相关代码。此外还需要手动添加一个Data Model文件。
在创建Data Model文件时需要注意文件名要与AppDelegate.m中managedObjectModel方法中提到的文件名称相匹配。
-
有了Data Model文件后,就可以在里面添加实体和关系,实际上就是向数据库中添加表格和建立表格之间的关联。
-
创建好实体后,可以通过添加NSManagedObject subclass文件,系统可以自动添加实体对应的数据模型类。
-
通过代码实现数据库的操作
-
插入数据
-(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]; }
-
-