iOS三种数据存储及优缺

1, 第一种数据存储方式:NSKeyedArchiver(归档),通过归档直接存储对象

遵守NSCoding协议,实现相应的方法就可以把该对象或者包含该对象的其他对象直接存储到文件,用起来相对简单,存储的时候是覆盖存储,取出的时候也是一次性全部取出文件中内容,所以如果是很多数据,用归档方式就比较耗费资源,不太合适,但是如不哦是小型数据,对象存储等就可以用归档方式

  • 1.0,需要用归档方式存储的对象必须要遵守NSCoding协议<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方法即可,这里不再赘述,如果还是不明白,之前的文章
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容