欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

IOS数据存储常用的5种方式

程序员文章站 2022-05-25 15:50:15
ios数据存储常用的5种方式。 ios应用数据存储的常用方式: 1> xml属性列表(plist)归档. 2> preference(偏好设置). 3> nskeyedarchiv...

ios数据存储常用的5种方式。

ios应用数据存储的常用方式:

1> xml属性列表(plist)归档.

2> preference(偏好设置).

3> nskeyedarchiver归档.

4> sqlite3

5> core data

应用沙盒:

每个ios应用都有自己的应用沙盒(应用沙盒就是文件目录)与其他文件系统隔离.应用必须待在自己的沙盒里,其他应用不能访问该沙盒.

模拟器应用沙盒的根路径在: (apple是用户名, 6.0是模拟器版本)

/users/apple/library/application support/iphone simulator/6.0/applications

或者:/users/用户名/资源库/application support/iphone simulator/6.1/applications

注意:

默认情况下,模拟器的目录是隐藏的,要想显示出来,需要在mac终端输入下面的命令:

显示mac隐藏文件的命令:defaults write com.apple.finder appleshowallfiles yes

隐藏mac隐藏文件的命令:defaults write com.apple.finder appleshowallfiles no

应用沙盒结构分析

documents:

保存应用运行时生成的需要持久化的数据,itunes同步设备时会备份该目录.例如游戏应用可将游戏存档保存在该目录.

temp:

保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除.应用没有运行时,系统也可能会清除该目录下的文件.itunes同步设备时不会备份该目录.

library/caches:

保存应用运行时生成的需要持久化的数据,itunes同步设备时不会备份该目录.一般存储体积大,不需要备份的非重要数据.

library/preference:

保存应用的所有偏好设置,ios的setting(设置)应用会在该目录中查找应用的设置信息.itunes同步设备时会备份该目录.

应用沙盒目录的常见获取方式:

沙盒根路径:

1nsstring*home=nshomedirectory();

documents:(2种方式)

1> 利用沙盒根目录拼接"documents"字符串:

1 2 3nsstring*home=nshomedirectory(); nsstring*documents=[homestringbyappendingpathcomponent:@"documents"]; //不建议采用,因为新版本的操作系统可能会修改目录名

2> 利用nssearchpathfordirectoriesindomains函数:

1 2 3 4 5//nsuserdomainmask代表从用户文件夹下找 //yes代表展开路径中的波浪字符“~” nsarray*array=nssearchpathfordirectoriesindomains(nsdocumentdirectory,nsuserdomainmask,no); //在ios中,只有一个目录跟传入的参数匹配,所以这个集合里面只有一个元素 nsstring*documents=[arrayobjectatindex:0];

tmp:

1nsstring*tmp=nstemporarydirectory();

library/catches:(跟documents类似的两种方法)

1> 利用沙盒跟目录拼接"catches"字符串.

2> 利用nssearchpathfordirectoriesindomains函数(将函数的第一个参数改为:nscachesdirectory即可).

library/preference:通过nsuserdefaults类存取该目录下的设置信息.

下面分别详细介绍5中数据存数方式.

属性列表

属性列表是一种xml格式的文件,拓展名为plist.

如果对象是nsstring, nsdictionary, nsarray, nsdata, nsnumber等类型,就可以使用:writetofile:atomiclly:方法直接将对象写到属性列表文件中.

属性列表-归档nsdictionary

将一个nsdictionary归档到一个plist属性列表中.

1 2 3 4 5 6//将数据封装成字典 nsmutabledictionary*dict=[nsmutabledictionarydictionary]; [dictsetobject:@"15013141314"forkey:@"phone"]; [dictsetobject:@"27"forkey:@"age"]; //将字典持久化到documents/stu.plist文件中 [dictwritetofile:pathatomically:yes];

属性列表-恢复nsdictionary

读取属性列表,恢复nsdictionary对象

1 2 3 4//读取documents/stu.plist的内容,实例化nsdictionary nsdictionary*dict=[nsdictionarydictionarywithcontentsoffile:path]; nslog(@"phone:%@",[dictobjectforkey:@"phone"]); nslog(@"age:%@",[dictobjectforkey:@"age"]);

偏好设置

很多ios应用都支持偏好设置,比如保存用户名,密码,是否自动登录等设置,ios提供了一套标准的解决方案来为应用加入偏好设置功能.

每个应用都有个nsuserdefaults实例,通过它来存取偏好设置.

如保存用户名,字体大小,是否登录

1 2 3 4nsuserdefaults*defaults=[nsuserdefaultsstandarduserdefaults]; [defaultssetobject:@"jn521"forkey:@"username"]; [defaultssetfloat:18.0fforkey:@"text_size"]; [defaultssetbool:yesforkey:@"auto_login"];

读取上次保存的设置

1 2 3 4nsuserdefaults*defaults=[nsuserdefaultsstandarduserdefaults]; nsstring*username=[defaultsstringforkey:@"username"]; floattextsize=[defaultsfloatforkey:@"text_size"]; boolautologin=[defaultsboolforkey:@"auto_login"];

注意:

userdefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘.所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了.出现此问题,可以通过调用synchornize方法强制写入.

1[defaultssynchornize];

nskeyedarchiver

如果对象是nsstring, nsdictionary, nsarray, nsdata, nsnumber等类型,就可以直接使用:nskeyedarchiver进行归档和恢复.

不是所有的对象都可以直接用这种方法进行归档,只有遵守了nscoding协议的的对象才可以.

nscoding协议有2个方法:

encodewithcoder:

每次归档对象时,都会调用这个方法.一般在这个方法里面指定如何归档对象中的每个实例变量.可以使用:encodeobject:forkey:方法归档实例变量.

initwithcoder:

每次从文件中恢复(解码)对象时,都会调用这个方法.一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeobject:forkey方法解码实例变量.

归档一个nsarray对象到documents/array.archive:

1 2 3nsstring*path=[nsstringstringwithformat:@"documents/array.archive"]; nsarray*array=[nsarrayarraywithobjects:@"a",@"b",nil]; [nskeyedarchiverarchiverootobject:arraytofile:path];

恢复(解码)nsarray对象

1nsarray*array=[nskeyedunarchiverunarchiveobjectwithfile:path];

nskeyedarchiver-归档person对象:

person.h中:

1 2 3 4 5@interfaceperson:nsobject @property(nonatomic,copy)nsstring*name; @property(nonatomic,assign)intage; @property(nonatomic,assign)floatheight; @end

person.m中:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25@implementationperson -(void)encodewithcoder:(nscoder*)encoder { [encoderencodeobject:self.nameforkey:@"name"]; [encoderencodeint:self.ageforkey:@"age"]; [encoderencodefloat:self.heightforkey:@"height"]; } -(id)initwithcoder:(nscoder*)decoder { self.name=[decoderdecodeobjectforkey:@"name"]; self.age=[decoderdecodeintforkey:@"age"]; self.height=[decoderdecodefloatforkey:@"height"]; returnself; } //归档(编码) person*person=[[personalloc]init]; person.name=@"jn"; person.age=22; person.height=1.63f; [nskeyedarchiverarchiverootobject:persontofile:path]; //恢复(解码) person*person=[nskeyedunarchiverunarchiveobjectwithfile:path]; @end

nskeyedarchiver-归档对象的注意

如果父类也遵守了nscoding协议,请注意:

1> 应该在uencodewithcoder:方法中加上一句[super encodewithcode:encode];确保继承的实例变量也能被编码,即也能被归档.

2> 应该在initwithcoder:方法中加上一句self = [super initwithcoder:decoder];确保继承的实例变量也能被解码,即也能被恢复.

更多:

使用nskeyedarichiver进行归档、nskeyedunarchiver进行接档,这种方式会在写入、读出数据之前对数据进行序列化、反序列化操作。

归档:

nsstring*homedictionary=nshomedirectory();//获取根目录

nsstring*homepath=[homedictionarystringbyappendingpathcomponent:@"atany.archiver"];//添加储存的文件名

boolflag=[nskeyedarchiverarchiverootobject:@”归档”tofile:homepath];//归档一个字符串

这种方式可以对字符串、数字等进行归档,当然也可以对nsarray与nsdictionary进行归档。返回值flag标志着是否归档成功,yes为成功,no为失败。

接档:

[nskeyedunarchiverunarchiveobjectwithfile:homepath]

使用nskeyedunarchiver进行接档(反序列化)。

这种归档的方式存在一个缺点:只能把一个对象归档进一个文件中,那么怎么对多个对象进行归档呢?

二、对多个对象的归档

同样是使用nskeyedarchiver进行归档,不同的是同时归档多个对象,这里我们举例放入了一个cgpoint点、字符串、整数(当然很多类型都可以的,例如uiimage、float等等),使用encodexxx方法进行归档,最后通过writetofile方法写入文件。

归档:写入数据

//准备数据

cgpointpoint=cgpointmake(1.0,2.0);

nsstring*info=@"坐标原点";

nsintegervalue=10;

nsstring*multihomepath=[nshomedirectory()stringbyappendingpathcomponent:@"multi.archiver"];

nsmutabledata*data=[[nsmutabledataalloc]init];

nskeyedarchiver*archvier=[[nskeyedarchiveralloc]initforwritingwithmutabledata:data];

//对多个对象进行归档

[archvierencodecgpoint:pointforkey:@"kpoint"];

[archvierencodeobject:infoforkey:@"kinfo"];

[archvierencodeinteger:valueforkey:@"kvalue"];

[archvierfinishencoding];

[datawritetofile:multihomepathatomically:yes];

接档:从路径中获得数据构造nskeyedunarchiver实例,使用decodexxxforkey方法获得文件中的对象。

nsmutabledata*datar=[[nsmutabledataalloc]initwithcontentsoffile:multihomepath];

nskeyedunarchiver*unarchiver=[[nskeyedunarchiveralloc]initforreadingwithdata:dater];

cgpointpointr=[unarchiverdecodecgpointforkey:@"kpoint"];

nsstring*infor=[unarchiverdecodeobjectforkey:@"kinfo"];

nsintegervaluer=[unarchiverdecodeintegerforkey:@"kvalue"];

[unarchiverfinishdecoding];

nslog(@"%f,%f,%@,%d",pointr.x,pointr.y,infor,valuer);

可以看出对多个对象进行归档还是挺方便的,这里又出现一个问题,这里的对象都是基本类型数据,那么怎么对自己定义类生成的实例对象进行归档呢?

三、对自定义对象进行归档

自定义对象,应用范围很广,因为它对应着mvc中的model层,即实体类。在程序中,我们会在model层定义很多的entity,例如user,teacher。。

那么对自定义对象的归档显得重要的多,因为很多情况下我们需要在home键之后保存数据,在程序恢复时重新加载,那么,归档便是一个好的选择。

首先我们需要,自定义一个实体类,archive。

archive.h

#import

@interfacearchive:nsobject

@property(copy,nonatomic)nsstring*name;

@propertynsintegerage;

@property(copy,nonatomic)nsstring*address;

@property(copy,nonatomic)uiimage*photo;

@end

archive.m

#import"archive.h"

#defineknamekey@"namekey"

#definekagekey@"agekey"

#definekaddress@"addresskey"

#definekphotokey@"photokey"

@implementationarchive

@synthesizename=_name;

@synthesizeage=_age;

@synthesizeaddress=_address;

@synthesizephoto=_photo;

#pragmamark-nscoding

-(void)encodewithcoder:(nscoder*)acoder{

[acoderencodeobject:_nameforkey:knamekey];

[acoderencodeinteger:_ageforkey:kagekey];

[acoderencodeobject:_addressforkey:kaddress];

[acoderencodeobject:_photoforkey:kphotokey];

}

-(id)initwithcoder:(nscoder*)adecoder{

if(self=[superinit]){

_name=[adecoderdecodeobjectforkey:knamekey];

_age=[adecoderdecodeintegerforkey:kagekey];

_address=[adecoderdecodeobjectforkey:kaddress];

_photo=[adecoderdecodeobjectforkey:kphotokey];

}

returnself;

}

#pragmamark-nscoping

-(id)copywithzone:(nszone*)zone{

archive*copy=[[[selfclass]allocwithzone:zone]init];

copy.name=[self.namecopywithzone:zone];

copy.age=self.age;

copy.address=[self.addresscopywithzone:zone];

copy.photo=self.photo;

returncopy;

}

@end

archive类有四个字段(名字、年纪、地址、头像),除了年纪为整型之外,其他的都看作object。

【注】:要将一个自定义的类进行归档,那么类里面的每个属性都必须是可以被归档的,如果是不能归档的类型,我们可以把他转化为nsvalue进行归档,然后在读出来的时候在转化为相应的类。

archive实现了三个委托方法1)encodewithcoder: 2)initwithcoder: 3)copywithzone:

1)encodewithcoder

encodes the receiverusing a given archiver

通过一个给定的archiver把消息接收者进行编码。

当接收到encodeobject消息的时候,类终端encodewithcoder方法被调用。

2)initwithcoder

returns an objectinitialized from data in a given unarchiver. (required)

从一个给定unarchiver的数据中返回一个初始化对象。

3)copywithzone

returnsa new instance that’s a copy of the receiver

返回消息接收者的一个复制的新实例。

sdk的概念就是这样,下面看看这个自定义类归档的具体代码,其实和多个对象的归档是一样的。。。