欢迎访问 生活随笔!

尊龙游戏旗舰厅官网

当前位置: 尊龙游戏旗舰厅官网 > 编程资源 > 编程问答 >内容正文

编程问答

ios五种本地缓存数据方式 -尊龙游戏旗舰厅官网

发布时间:2025/1/21 编程问答 8 豆豆
尊龙游戏旗舰厅官网 收集整理的这篇文章主要介绍了 ios五种本地缓存数据方式 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
ios五种本地缓存数据方式

ios本地缓存数据方式有五种:前言

1.直接写文件方式:可以存储的对象有nsstring、nsarray、nsdictionary、nsdata、nsnumber,数据全部存放在一个属性列表文件(*.plist文件)中。

2.nsuserdefaults(偏好设置),用来存储应用设置信息,文件放在perference目录下。

3.归档操作(nskeyedarchiver),不同于前面两种,它可以把自定义对象存放在文件中。

4.coredata:coredata是苹果官方ios5之后推出的综合型数据库,其使用了orm(object relational mapping)对象关系映射技术,将对象转换成数据,存储在本地数据库中。coredata为了提高效率,甚至将数据存储在不同的数据库中,且在使用的时候将本地数据放到内存中使得访问速度更快。我们可以选择coredata的数据存储方式,包括sqlite、xml等格式。但也正是coredata 是完全面向对象的,其在执行效率上比不上原生的数据库。除此之外,coredata拥有数据验证、undo等其他功能,在功能上是几种持久化方案最多的。

5.fmdb:fmdb是ios平台的sqlite数据库框架,fmdb以oc的方式封装了sqlite的c语言api,使用起来更加面向对象,省去了很多麻烦、冗余的c语言代码,对比苹果自带的core data框架,更加轻量级和灵活,提供了多线程安全的数据库操作方法,有效地防止数据混乱。

//获取沙盒中缓存文件夹路径

//方法一

//沙盒主目录

nsstring *homepath = nshomedirectory();

//拼接路径

nsstring *path = [homepath stringbyappendingpathcomponent:@"library/caches"];

//方法二

//第一个参数目标文件夹目录(nscachesdirectory查找缓存文件夹),第二个参数为查找目录的域(nsuserdomainmask为在用户目录下查找),第三个参数为结果中主目录是否展开,不展开则显示为~

nsarray *arr = nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes);

//虽然该方法返回的是一个数组,但是由于一个目标文件夹只有一个目录,所以数组中只有一个元素。

nsstring *cachepath = [arr lastobject];

//或者

// nsstring *cachepath = [arr objectatindex:0];

/**

//获取沙盒中document文件夹或者tmp文件夹路径都可使用上面两种方法

//tmp文件夹路径可直接这样获取

nsstring *tmppath = nstemporarydirectory();

nslog(@"%@",tmppath);

**/

//拼接路径(目标路径),这个时候如果目录下不存在这个lotheve.plist文件,这个目录实际上是不存在的。

nsstring *filepath = [cachepath stringbyappendingpathcomponent:@"tese.plist"];

nslog(@"%@",filepath);

//创建数据

nsdictionary *content = @{@"字典数据测试1":@"1",@"字典数据测试2":@"2",@"字典数据测试":@"3"};

//将数据存到目标路径的文件中(这个时候如果该路径下文件不存在将会自动创建)

//用writetofile方法写文件会覆盖掉原来的内容

[content writetofile:filepath atomically:yes];

//读取数据(通过字典的方式读出文件中的内容)

nsdictionary *dic = [nsdictionary dictionarywithcontentsoffile:filepath];

nslog(@"%@",dic);

沙盒中library/caches目录下多了lotheve.plist文件:


文件内容:


达人教路游澳门 【点击进入】 寻找澳门人文踪迹,发现不一样的澳门 北京澳门机票特惠,十月往返2000起 查 看


如何获取模拟器沙盒路径:

打印日志,复制路径打开mac finder,点击左上角菜单前往,前往文件夹,把路径粘贴上去。

nsstring *path = [nssearchpathfordirectoriesindomains(nsdocumentdirectory,nsuserdomainmask,yes) objectatindex:0];

nslog(@"%@",path);

方式二:nsuserdefaults(偏好设置)

每个应用都有一个nsuesrdefaults实例,通过它可以存储应用配置信息以及用户信息,比如保存用户名、密码、字体大小、是否自动登录等等。数据自动保存在沙盒的libarary/preferences目录下。同样,该方法只能存取nsstring、nsarray、nsdictionary、nsdata、nsnumber类型的数据。

属性列表是一种明文的轻量级存储方式,其存储格式有多种,最常规格式为xml格式。在我们创建一个新的项目的时候,xcode会自动生成一个info.plist文件用来存储项目的部分系统设置。plist只能用数组(nsarray)或者字典(nsdictionary)进行读取,由于属性列表本身不加密,所以安全性几乎可以说为零。因为,属性列表正常用于存储少量的并且不重要的数据。

在程序启动后,系统会自动创建一个nsuserdefaults的单例对象,我们可以获取这个单例来存储少量的数据,它会将输出存储在.plist格式的文件中。其优点是像字典一样的赋值方式方便简单,但缺点是无法存储自定义的数据。

代码示例:

//点击button保存数据

- (ibaction)savedata:(id)sender {

//获取nsuserdefaults对象

nsuserdefaults *userdefaults = [nsuserdefaults standarduserdefaults];

//存数据,不需要设置路劲,nsuserdefaults将数据保存在preferences目录下

[userdefaults setobject:@"lotheve" forkey:@"name"];

[userdefaults setobject:@"nsuserdefaults" forkey:@"demo"];

//立刻保存(同步)数据(如果不写这句话,会在将来某个时间点自动将数据保存在preferences目录下)

[userdefaults synchronize];

nslog(@"数据已保存");

}

//点击button读取数据

- (ibaction)getdata:(id)sender

{

//获取nsuserdefaults对象

nsuserdefaults *userdefaults = [nsuserdefaults standarduserdefaults];

//读取数据

nsstring *name = [userdefaults objectforkey:@"name"];

nsstring *demo = [userdefaults objectforkey:@"demo"];

//打印数据

nslog(@"name = %@ demo =%@",name,demo);

}

点击“保存数据”后,查看沙盒中的libarary/ preferences目录:


达人教路游澳门 【点击进入】 寻找澳门人文踪迹,发现不一样的澳门 北京澳门机票特惠,十月往返2000起 查 看

数据以plist的格式写入磁盘中了。点开查看数据:

方式三:nskeyedarchiver(归档操作)

与属性列表相反,同样作为轻量级存储的持久化方案,数据归档是进行加密处理的,数据在经过归档处理会转换成二进制数据,所以安全性要远远高于属性列表。另外使用归档方式,我们可以将复杂的对象写入文件中,并且不管添加多少对象,将对象写入磁盘的方式都是一样的。

使用nskeyedarchiver对自定义的数据进行序列化,并且保存在沙盒目录下。使用这种归档的前提是让存储的数据模型遵守nscoding协议并且实现其两个协议方法。(当然,如果为了更加安全的存储,也可以遵守nssecurecoding协议,这是ios6之后新增的特性)

使用归档操作存储数据的主要好处是,不同于前面两种方法只能存储几个常用的数据类型的数据,nskeyedarchiver可以存储自定义的对象。

代码示例:

先创建一个继承nsobject的类,该类遵守nscoding协议

testperson.h

@interface testperson : nsobject

@property (nonatomic, copy) nsstring *name;

@property (nonatomic, assign) nsinteger age;

@property (nonatomic, copy) nsstring *sex;

@property (nonatomic, strong) nsarray *familymumbers;

@end

testperson.m

#import "testperson.h"

@interface testperson ()

@end

@implementationtestperson

- (void)viewdidload

{

[super viewdidload];

}

#pragma mark - nscoding协议方法 (一定要实现)

//当进行归档操作的时候就会调用该方法

//在该方法中要写清楚要存储对象的哪些属性

- (void)encodewithcoder:(nscoder *)acoder

{

nslog(@"调用了encodewithcoder方法");

[acoder encodeobject:_name forkey:@"name"];

[acoder encodeinteger:_age forkey:@"age"];

[acoder encodeobject:_sex forkey:@"sex"];

[acoder encodeobject:_familymumbers forkey:@"familymumbers"];

}

//当进行解档操作的时候就会调用该方法

//在该方法中要写清楚要提取对象的哪些属性

- (id)initwithcoder:(nscoder *)adecoder

{

nslog(@"调用了initwithcoder方法");

if (self = [super init]) {

self.name = [adecoder decodeobjectforkey:@"name"];

self.age = [adecoder decodeintegerforkey:@"age"];

self.sex = [adecoder decodeobjectforkey:@"sex"];

_familymumbers = [adecoder decodeobjectforkey:@"familymumbers"];

}

return self;

}

@end

这里还要讲一下一个小技巧:使用static修饰来替代宏定义。上面的序列化中,我们可以看到nscoding的协议方法中对数据进行序列化并且使用一个key来保存它。正常情况下我们可以使用宏来定义key,但是过多的宏定义在编译时也会造成大量的损耗。这时候可以使用static定义静态变量来取代宏定义。

static nsstring * const kusernamekey = @"username";

让自定义的数据遵循nscoding协议后,我们就能使用nskeyedarchiver和nskeyedunarchiver来对持久化的数据进行存取操作了:

- (ibaction)savedata:(id)sender

{

//创建一个自定义类的实例

_p = [[testperson alloc]init];

_p.name = @"lotheve";

_p.age = 20;

_p.sex = @"m";

_p.familymumbers = @[@"father",@"mather",@"me"];

//获取文件路径

nsstring *docpath = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];

//文件类型可以随便取,不一定要正确的格式

nsstring *targetpath = [docpath stringbyappendingpathcomponent:@"lotheve.plist"];

//将自定义对象保存在指定路径下

[nskeyedarchiver archiverootobject:_p tofile:targetpath];

nslog(@"文件已储存");

}

- (ibaction)getdata:(id)sender

{

//获取文件路径

nsstring *docpath = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];

nsstring *targetpath = [docpath stringbyappendingpathcomponent:@"lotheve.plist"];

testperson *person = [nskeyedunarchiver unarchiveobjectwithfile:targetpath];

nslog(@"name = %@ , age =%ld , sex = %@ , familymubers = %@",person.name,person.age,person.sex,person.familymumbers);

nslog(@"文件已提取");

}

点击“保存数据”后,查看沙盒中documents目录:



点击查看文件内容:


达人教路游澳门 【点击进入】 寻找澳门人文踪迹,发现不一样的澳门 北京澳门机票特惠,十月往返2000起 查 看

点击“提取数据”后打印结果:

方式四:coredata

coredata是ios5之后苹果推出的数据持久化框架,其提供了orm的功能,将对象和数据相互转换。其中,它提供了包括sqlite、xml、plist等本地存储文件,默认使用sqlite进行存储。coredata具有两个模型:关系模型和对象模型,关系模型即是数据库,对象模型为oc对象。其关系图如下:


由于我们不需要关心数据的存储,coredata使用起来算是最简单的持久化方案。要使用coredata有两个方式,一个是在创建项目的时候勾选use core data,另一个则是手动创建。在这里我们要讲解的是前者创建的方式:

1、创建新项目勾选使用coredata




2、创建关系模型,在这里我创建的模型名字是lxdcoredatademo(注意名字一定要和项目名称保持一致)


3、在创建的关系模型中添加实体,命名为person,并且添加三个字段:name、age、score


到了这里我们的实体模型就创建好了,接下来就是通过nsmanagedobject来将实体模型转换成对象。通过从coredata取出的对象,全部都是继承自nsmanagedobject的子类。那么我们需要根据当前的关系模型来创建person类


选择lxdcoredatademo -> next -> person -> create,我们就创建好了person,这时候三个成员属性都会自动添加完成


在执行操作的类实现文件中,我们要加入appdelegate和person的头文件,因为在创建项目的时候如果我们勾选了use core data的选项,appdelegate文件中会帮我们生成用于管理、存储这些模型的对象,我们可以通过添加头文件来使用。插入数据的代码如下:


//先取出coredata上下文管理者

appdelegate *appdelegate = [[uiapplication sharedapplication] delegate];

nsmanagedobjectcontext *context = appdelegate.managedobjectcontext;

//保存新数据

person *person = [nsentitydescription insertnewobjectforentityforname: @"person" inmanagedobjectcontext: context];

person.name = @"czk"

person.score = [nsnumber numberwithint:100];

person.age = [nsnumber numberwithint:25];

[appdelegate savecontext];

//查询所有数据

nserror *error;

nsfetchrequest *request = [nsfetchrequest new];

nsentitydescription *entity = [nsentitydescription entityforname: @"person" inmanagedobjectcontext: context];

[request setentity: entity];

nsarray *results = [[context executefetchrequest: request error: &error] copy];

for (person *p in results) {

nslog(@"%@, %@, %@", p.name, p.age, p.score);

}

注意:如果出现崩溃异常,请卸载app后重新安装。

方式五:fmdb

优点:

对多线程的并发操作进行处理,所以是线程安全的;

以oc的方式封装了sqlite的c语言api,使用起来更加的方便;

fmdb是轻量级的框架,使用灵活。

缺点:

因为它是oc的语言封装的,只能在ios开发的时候使用,所以在实现跨平台操作的时候存在局限性。

fmdb有三个主要的类

(1)fmdatabase

一个fmdatabase对象就代表一个单独的sqlite数据库

用来执行sql语句

(2)fmresultset

使用fmdatabase执行查询后的结果集

(3)fmdatabasequeue

用于在多线程中执行多个查询或更新,它是线程安全的

这里建议使用cocoapods导入fmdb,关于cocoapods的使用这里就不啰嗦了。

创建数据库:

db=[fmdatabasedatabasewithpath:database_path];

1、当数据库文件不存在时,fmdb会自己创建一个。

2、 如果你传入的参数是空串:@"" ,则fmdb会在临时文件目录下创建这个数据库,数据库断开连接时,数据库文件被删除。

3、如果你传入的参数是 null,则它会建立一个在内存中的数据库,数据库断开连接时,数据库文件被删除。

打开数据库:

[dbopen];

返回bool型。

关闭数据库:

[dbclose];

数据库增删改等操作:

除了查询操作,fmdb数据库操作都执行executeupdate方法,这个方法返回bool型。



看一下例子:

创建表:

if([dbopen]){

nsstring*sqlcreatetable=[nsstringstringwithformat:@"createtableifnotexists'%@'('%@'integerprimarykeyautoincrement,'%@'text,'%@'integer,'%@'text)",tablename,id,name,age,address];

boolres=[dbexecuteupdate:sqlcreatetable];

if(!res){

nslog(@"errorwhencreatingdbtable");

}else{

nslog(@"successtocreatingdbtable");

}

[dbclose];

}

添加数据:

if([dbopen]){

nsstring*insertsql1=[nsstringstringwithformat:

@"insertinto'%@'('%@','%@','%@')values('%@','%@','%@')",

tablename,name,age,address,@"张三",@"13",@"济南"];

boolres=[dbexecuteupdate:insertsql1];

nsstring*insertsql2=[nsstringstringwithformat:

@"insertinto'%@'('%@','%@','%@')values('%@','%@','%@')",

tablename,name,age,address,@"李四",@"12",@"济南"];

boolres2=[dbexecuteupdate:insertsql2];

if(!res){

nslog(@"errorwheninsertdbtable");

}else{

nslog(@"successtoinsertdbtable");

}

[dbclose];

}

修改数据:

if([dbopen]){

nsstring*updatesql=[nsstringstringwithformat:

@"update'%@'set'%@'='%@'where'%@'='%@'",

tablename,age,@"15",age,@"13"];

boolres=[dbexecuteupdate:updatesql];

if(!res){

nslog(@"errorwhenupdatedbtable");

}else{

nslog(@"successtoupdatedbtable");

}

[dbclose];

}

删除数据:

if([dbopen]){

nsstring*deletesql=[nsstringstringwithformat:

@"deletefrom%@where%@='%@'",

tablename,name,@"张三"];

boolres=[dbexecuteupdate:deletesql];

if(!res){

nslog(@"errorwhendeletedbtable");

}else{

nslog(@"successtodeletedbtable");

}

[dbclose];

}

数据库查询操作:

查询操作使用了executequery,并涉及到fmresultset。

if([dbopen]){

nsstring*sql=[nsstringstringwithformat:

@"select*from%@",tablename];

fmresultset*rs=[dbexecutequery:sql];

while([rsnext]){

intid=[rsintforcolumn:id];

nsstring*name=[rsstringforcolumn:name];

nsstring*age=[rsstringforcolumn:age];

nsstring*address=[rsstringforcolumn:address];

nslog(@"id=%d,name=%@,age=%@address=%@",id,name,age,address);

}

[dbclose];

}

fmdb的fmresultset提供了多个方法来获取不同类型的数据:


数据库多线程操作:


如果应用中使用了多线程操作数据库,那么就需要使用fmdatabasequeue来保证线程安全了。 应用中不可在多个线程中共同使用一个fmdatabase对象操作数据库,这样会引起数据库数据混乱。 为了多线程操作数据库安全,fmdb使用了fmdatabasequeue,使用fmdatabasequeue很简单,首先用一个数据库文件地址来初使化fmdatabasequeue,然后就可以将一个闭包(block)传入indatabase方法中。 在闭包中操作数据库,而不直接参与fmdatabase的管理。

fmdatabasequeue * queue = [fmdatabasequeue databasequeuewithpath:database_path];

dispatch_queue_tq1=dispatch_queue_create("queue1",null);

dispatch_queue_tq2=dispatch_queue_create("queue2",null);

dispatch_async(q1,^{

for(inti=0;i<50; i){

[queueindatabase:^(fmdatabase*db2){

nsstring*insertsql1=[nsstringstringwithformat:

@"insertinto'%@'('%@','%@','%@')values(?,?,?)",

tablename,name,age,address];

nsstring*name=[nsstringstringwithformat:@"jack%d",i];

nsstring*age=[nsstringstringwithformat:@"%d",10 i];

boolres=[db2executeupdate:insertsql1,name,age,@"济南"];

if(!res){

nslog(@"errortoinsterdata:%@",name);

}else{

nslog(@"succtoinsterdata:%@",name);

}

}];

}

});

dispatch_async(q2,^{

for(inti=0;i<50; i){

[queueindatabase:^(fmdatabase*db2){

nsstring*insertsql2=[nsstringstringwithformat:

@"insertinto'%@'('%@','%@','%@')values(?,?,?)",

tablename,name,age,address];

nsstring*name=[nsstringstringwithformat:@"lilei%d",i];

nsstring*age=[nsstringstringwithformat:@"%d",10 i];

boolres=[db2executeupdate:insertsql2,name,age,@"北京"];

if(!res){

nslog(@"errortoinsterdata:%@",name);

}else{

nslog(@"succtoinsterdata:%@",name);

}

}];

}

});

总结:

上面已经分别介绍了五种方案的优缺点,在开发中,并没有说哪种持久化方案是最好的,只能说在不同开发场景下,最适合使用的持久化方案。

总结

以上是尊龙游戏旗舰厅官网为你收集整理的ios五种本地缓存数据方式的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得尊龙游戏旗舰厅官网网站内容还不错,欢迎将尊龙游戏旗舰厅官网推荐给好友。

网站地图