1, 第一种数据存储方式:NSKeyedArchiver(归档),通过归档直接存储对象
遵守NSCoding协议,实现相应的方法就可以把该对象或者包含该对象的其他对象直接存储到文件,用起来相对简单,存储的时候是覆盖存储,取出的时候也是一次性全部取出文件中内容,所以如果是很多数据,用归档方式就比较耗费资源,不太合适,但是如不哦是小型数据,对象存储等就可以用归档方式
- 1.0,需要用归档方式存储的对象必须要遵守NSCoding协议
,实现内部方法,如下:
//归档协议(存储的时候调用)
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInteger:_age forKey:@"age"];
}
//解档协议(从文件中读取数据的时候调用)
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = (int)[aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
- 1.1, 把对象归档到文件
//把对象归档到文件(注意:如要归档,该对象是需要先遵守NSCoding协议,并实现相应的方法)
[NSKeyedArchiver archiveRootObject:dog toFile:@"/users/feng/desktop/dogs.plist"];
- 1.2, 从文件中解档,得到对象
//从文件中解档,得到对象
IMDog *dog01 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/users/feng/desktop/dogs.plist"];
NSLog(@"%@", dog01);
- 1.3, 拓展,进行多个数据的存储,可以直接放进数组中进行,如下:
//NSKeyedArchiver(归档)拓展:一次性存储n多数据
NSMutableArray *dogsArray = [NSMutableArray array];
for (int i=0; i<100; i++) {
NSString *name = [NSString stringWithFormat:@"zhang-%d",i];
int age = arc4random_uniform(100);
IMDog *dog = [IMDog dogWithName:name age:age];
[dogsArray addObject:dog];
}
//归档
[NSKeyedArchiver archiveRootObject:dogsArray toFile:@"/users/feng/desktop/dogsArray.plist"];
//解档
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:@"users/feng/desktop/dogsArray.plist"];
//解析数据:取出其中第10-20之间的数据
NSArray *result = [array subarrayWithRange:NSMakeRange(10, 10)];
[result enumerateObjectsUsingBlock:^(IMDog *dog, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"name:%@---age:%d", dog.name, dog.age);
}];
2,sql存储(FMDB框架):
fmdb框架是对sql的封装,适合大型数据存储,读取过滤方便,耗费资源较少
但是sql是不能直接存储对象的,可以把对象通过nscoding转换成二进制数据后在进行存储
*2.1 ,普通类型数据逐个插入:
//1,创建数据库并打开
_db = [FMDatabase databaseWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"dogs.sqlite"]];
[_db open];
//2, 创表
[_db executeUpdate:@"create table if not exists t_dogs (id integer primary key, name text, age integer);"];
//3,增加数据
for (int i=0; i<100; i++) {
NSString *name = [NSString stringWithFormat:@"zhang-%d",i];
int age = arc4random_uniform(100);
[_db executeUpdateWithFormat:@"insert into t_dogs (name, age) values (%@,%d);",name, age];
}
//4,查询数据
FMResultSet *resultRet = [_db executeQuery:@"select * from t_dogs where age > 30"];
while (resultRet.next) {
NSString *name = [resultRet stringForColumn:@"name"];
//age虽然是int类型,但是这里仍旧可以用stringForColumn:取出字段对应的值,因为本质上来讲,sql是没有类型之分的
NSString *age = [resultRet stringForColumn:@"age"];
NSLog(@"%@@@@---@@@%@", name, age);
}
- 2.2, 对象类型逐个插入:(其实之前的微博存储也是逐个存储,因为它是一条微博存储一次,并不是把所有微博放在一个数组里存储的):
需要先把对象转换成二进制数据
//1,创建数据库并打开
_db = [FMDatabase databaseWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"dogsObject.sqlite"]];
[_db open];
//2, 创表(之所以在后面多加一个age字段是为了方便进行条件过滤)
[_db executeUpdate:@"create table if not exists t_dogs (id integer primary key, dog blob not null, age integer not null);"];
//3,增加数据
for (int i=0; i<100; i++) {
NSString *name = [NSString stringWithFormat:@"zhang-%d",i];
int age = arc4random_uniform(100);
IMDog *dog = [IMDog dogWithName:name age:age];
NSData *dogData = [NSKeyedArchiver archivedDataWithRootObject:dog];
[_db executeUpdateWithFormat:@"insert into t_dogs (dog, age) values (%@,%d);", dogData, age];
}
//4,查询数据
FMResultSet *resultRet = [_db executeQuery:@"select * from t_dogs where age > 30"];
while (resultRet.next) {
NSData *dogData = [resultRet dataForColumn:@"dog"];
IMDog *dog = [NSKeyedUnarchiver unarchiveObjectWithData:dogData];
NSLog(@"%@@@@---@@@%d", dog.name, dog.age);
}
*2.3, 把对象放入到数组中进行批量存储
- 需要先把数组转换成二进制数据存储
- 这种方法存储方便,但是在取出的时候没有办法进行相应的排序,其实微博项目的存储应该属于第二种情况,因为它虽然存储的是二进制数据,但是并不是所有的微博放在一起存储,而是一个微博一个微博转换成二进制数据进行存储。
//1,创建数据库并打开
_db = [FMDatabase databaseWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"dogs_extension.sqlite"]];
[_db open];
//2, 创表
[_db executeUpdate:@"create table if not exists t_dogs (id integer primary key, dogs blob not null);"];
//3,增加数据
NSMutableArray *dogs = [NSMutableArray array];
for (int i=0; i<100; i++) {
NSString *name = [NSString stringWithFormat:@"zhang-%d",i];
int age = arc4random_uniform(100);
IMDog *dog = [IMDog dogWithName:name age:age];
[dogs addObject:dog];
}
//在往数据库中插入数据需要先转换成二进制数据
NSData *dogsData = [NSKeyedArchiver archivedDataWithRootObject:dogs];
[_db executeUpdateWithFormat:@"insert into t_dogs (dogs) values (%@);",dogsData];
//4,查询数据
FMResultSet *resultRet = [_db executeQuery:@"select * from t_dogs"];
while (resultRet.next) {
NSData *dogsData = [resultRet objectForColumnName:@"dogs"];
NSArray *dogArray = [NSKeyedUnarchiver unarchiveObjectWithData:dogsData];
[dogArray enumerateObjectsUsingBlock:^(IMDog *dog, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@---%d",dog.name, dog.age);
}];
}
- 2.4, 删除数据(执行一句sql语句即可)
//5,删除数据
[_db executeUpdate:@"delete from t_dogs where age > 60"];
3,coreData存储:
coreData是iOS自带的数据存储方式,是苹果对sql的封装,优点是可以直接进行对象保存操作(虽然不能说可以直接保存对象,但是可以直接对对象操作,保存对象方便),个人感觉缺点是创建起来比较麻烦,而且效率相对sql的话可能会低一些,因为它的本质是自动生成sql语句
- 之前的文章中有介绍到过CoreData,这里重新再复习一下咯:
首先讲一个易错的地方,就是创建对象的时候不是alloc,init方式,而是用下面的方式:
Dogs *dog = [NSEntityDescription insertNewObjectForEntityForName:@"Dogs" inManagedObjectContext:_context];
- 3.1, CoreData的创建
//1,首先找到模型文件路径,并初始化并把模型与模型路径关联起来
NSURL *url = [[NSBundle mainBundle] URLForResource:@"Dogs" withExtension:@"momd"];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
//2, 初始化并创建永久存储器,并关联存储器和模型
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Dogs.sqlite"];
NSURL *url01 = [NSURL fileURLWithPath:path];//指定存储的文件名
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url01 options:nil error:nil];
//3,初始化并创建上下文,并设置上下文中的永久存储器
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_context.persistentStoreCoordinator = coordinator;
- 3.2, 插入数据
//4,创建对象并添加(其实都是通过上下文进行操作的)
//插入单个数据
Dogs *dog = [NSEntityDescription insertNewObjectForEntityForName:@"Dogs" inManagedObjectContext:_context];
dog.name = @"zhangdanfeng";
dog.age = @20;
NSError *error;
[_context save:&error];
if (!error) {
NSLog(@"dog数据插入成功");
}
//批量插入数据
for (int i=0; i<100; i++) {
Dogs *dog = [NSEntityDescription insertNewObjectForEntityForName:@"Dogs" inManagedObjectContext:_context];
dog.name = [NSString stringWithFormat:@"zhangdanfeng--%d",i];
dog.age = @(arc4random_uniform(100));
NSError *error;
[_context save:&error];
if (!error) {
NSLog(@"批量数据插入成功");
}
}
- 3.3, 读取数据/查询数据
//5,读取数据
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Dogs"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age > 30"];
request.predicate = predicate;
NSError *error;
NSArray *array = [_context executeFetchRequest:request error:&error];
if (!error) {
NSLog(@"数据读取成功");
}
[array enumerateObjectsUsingBlock:^(Dogs *dog, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@!!!!!!%@",dog.name, dog.age);
}];
- 3.4, 删除数据
删除数据是建立在查询数据的基础上,即查询到指定数据后通过上下文直接把对象删除,然后重新保存上下文即可
//6,删除数据
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Dogs"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age > 20"];
request.predicate = predicate;
NSError *error;
NSArray *array = [_context executeFetchRequest:request error:&error];
if (!error) {
NSLog(@"查询到结果");
//查询到之后就可以直接通过上下文对对象进行删除操作
[array enumerateObjectsUsingBlock:^(Dogs *dog, NSUInteger idx, BOOL * _Nonnull stop) {
[_context deleteObject:dog];
[_context save:nil];
}];
}
- 3.5, 更新数据同删除数据基本一致,只需要重新赋值之后,把deleteObject:方法换成updatedObjects方法即可,这里不再赘述,如果还是不明白,之前的文章