概念
所谓持久化就是将数据保存到硬盘中,使得应用重启或者机器重启后可以继续访问之前保存的数据。
方案
- 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];
}
-