IOS数据存储常用的5种方式
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的概念就是这样,下面看看这个自定义类归档的具体代码,其实和多个对象的归档是一样的。。。
上一篇: iOS应用内支付(IAP)详解
下一篇: 心里过意不去