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

iOS数据持久化——属性列表和归档

程序员文章站 2023-03-28 07:56:03
ios数据持久化的方式分为三种 属性列表 (自定义的property list 、nsuserdefaults) 归档 (nskeyedarchiver) (sqlite、core data、第三...

ios数据持久化的方式分为三种

属性列表 (自定义的property list 、nsuserdefaults)

归档 (nskeyedarchiver)

(sqlite、core data、第三方类库等)

本文只介绍:属性列表和归档

一. 属性列表

plist一般用于存储dictionary、array、boolean、data、date、number、string这些类型的数据,但boolean、data、date、number、string类型的数据一般不直接存入plist文件中,因为plist文件有分层的概念,一般用nsdictionary或nsarray作为容器,再把其他数据类型装入,最后把容器存入plist文件。plist文件不能直接存储自定义的类,需要进行转化成上述的数据类型,才能存储。

(一). 数据的简单存储

nsdictionary或nsarray使用writetofile:atomically:方法,会默认存储到plist文件

    // 获取沙盒中documents目录的路径
    nsstring *documentspath = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes)[0];

    // 拼接路径
    nsstring *someobjpath = [documentspath stringbyappendingpathcomponent:@"someobj.plist"];

    // 要写入文件的数组
    nsarray *someobj = @[@"aaa",@"bbb",@999,@'a',@[@{@"name":@"小明"}]];

    // 把数组写入plist文件
    // 第一个参数是文件名,第二个参数为是否使用辅助文件,如果为yes,则先写入到一个辅助文件,然后辅助文件再重新命名为目标文件,
    // 如果为no,则直接写入到目标文件
    [someobj writetofile:someobjpath atomically:yes];

(二). nsfilemanager常用的文件管理

创建目录 createdirectoryatpath:

创建文件 createfileatpath:

删除某个文件 removeitematpath:

检查某个文件是否存在 fileexistsatpath:

检查文件是否可读 isreadablefileatpath:

是否可写:iswritablefileatpath:

取得文件属性 fileattributesatpath:

改变文件属性changeattributesatpath:

从path代表的文件中读取数据:contentsatpath

移动文件movepath:topath:handler:

复制文件copypath:topath:handler:

    // 1. 在沙盒里新建目录,再在目录里新建文件夹
    // 创建一个文件管理器
    nsfilemanager *filemanager = [nsfilemanager defaultmanager];

    // 获取沙盒下的documents路径
    nsstring *documentspath = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes).firstobject;

    // 拼接路径
    nsstring *newfilepath = [documentspath stringbyappendingpathcomponent:@"newfile"];

    // 创建新目录
    [filemanager createdirectoryatpath:newfilepath withintermediatedirectories:yes attributes:nil error:nil];


      // 读写数据一
    // 2. 向filenew.plist写入数据
    // 把路径改变到新路径下
    [filemanager changecurrentdirectorypath:[newfilepath stringbyexpandingtildeinpath]];

    // 创建filenew.plist文件
    [filemanager createfileatpath:@"filenew.plist" contents:nil attributes:nil];

    // 写入数据
    nsarray *dataarr = @[@[@100,@"study"],@{@"name":@"xiaoming"}];

    // 拼接filenew.plist路径
    nsstring *datapath = [newfilepath stringbyappendingpathcomponent:@"filenew.plist"];

    // 把数组写入filenew.plist
    [dataarr writetofile:datapath atomically:yes];


    // 3. 读取filenew.plist数据
    nsarray *arrdata = [nsarray arraywithcontentsoffile:datapath];

    nslog(@"%@",arrdata);



    // 读写数据二
    // 使用nsmutabledata存储数据要记住存储的顺序,读取数据时要要根据那个顺序计算每个数据所处的位置
    // 2. 向filename文件写入数据
    // 待写入的数据
    nsstring *datastr = @"new friend";
    int dataint = 666;
    float datafloat = 3.14159f;

    // 拼接存储数据的路径
    nsstring *datapath2 = [newfilepath stringbyappendingpathcomponent:@"filename"];

    //创建数据缓冲
    nsmutabledata *writerdata = [[nsmutabledata alloc] init];

    //将字符串添加到缓冲中
    [writerdata appenddata:[datastr datausingencoding:nsutf8stringencoding]];

    //将其他数据添加到缓冲中
    [writerdata appendbytes:&dataint length:sizeof(dataint)];
    [writerdata appendbytes:&datafloat length:sizeof(datafloat)];

    //将缓冲的数据写入到文件中
    [writerdata writetofile:datapath2 atomically:yes];


    // 3. 读取数据:
    // 读取filename文件中的数据
    nsdata *readerdata = [nsdata datawithcontentsoffile:datapath2];

    // 计算datastr在datastr的区间,并获取字
    datastr = [[nsstring alloc] initwithdata:[readerdata subdatawithrange:nsmakerange(0, [datastr length])]
                                   encoding:nsutf8stringencoding];

    // 计算dataint在datastr的区间,并获取
    [readerdata getbytes:&dataint range:nsmakerange([datastr length], sizeof(dataint))];

    // 计算datafloat在datastr的区间,并获取
    [readerdata getbytes:&datafloat range:nsmakerange([datastr length] + sizeof(dataint), sizeof(datafloat))];

    nslog(@"datastr:%@   dataint:%d   datafloat:%f", datastr,dataint,datafloat);


    // 删除filename文件
    [filemanager removeitematpath:@"filename" error:nil];

    // 删除一个目录:
    // currentdirectorypath:当前目录
    nslog(@"%@",filemanager.currentdirectorypath);
    [filemanager removeitematpath:filemanager.currentdirectorypath error:nil];

二. 偏好设置

(一). 知识点

偏好设置的本质还是plist文件存储,相对于plist文件存储来讲存储数据更快捷,不需要获取全路径。

偏好设置用来保存应用程序设置和属性、用户保存的数据,当用户再次打开程序或开机后这些数据仍然存在。

很多ios应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,ios也提供了一套标准的解决方案来为应用加入偏好设置功能。 每个ios应用都有一个nsuserdefaults实例,它是一个单例对象,通过它来存取偏好设置,设置信息都是键值对的形式。 用userdefaults实例设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘,所以调用了set方法之后数据有可能还没有写入磁盘,如果应用程序突然终止了,数据有可能写入不成功。 偏好设置是专门用来保存应用程序的配置信息的, 一般情况不要在偏好设置中保存其他数据。 如果利用的偏好设置来存储数据, 默认就是存储在preferences文件夹下面的,偏好设置会将所有的数据都保存到同一个文件中。 偏好设置针对同一个关键字对应的对象或者数据,可以对它进行重写,重写之后关键字就对应新的对象或者数据,旧的对象或者数据会被自动清理。 使用偏好设置对数据进行保存之后, 它保存到系统的时间是不确定的,会在将来某一时间点自动将数据保存到preferences文件夹下面,如果需要即刻将数据存储,可以使用[defaults synchronize];强制写入偏好设置文件。 ios7之后,如果不写[defaults synchronize];,数据也会同步存储。

(二). 具体使用

    nsuserdefaults *userdefaults = [nsuserdefaults standarduserdefaults];

    [userdefaults setvalue:@"小明" forkey:@"name"];
    [userdefaults setvalue:@"男" forkey:@"sex"];
    [userdefaults setvalue:@"学生" forkey:@"work"];

    // 写入磁盘
    [userdefaults synchronize];

    nslog(@"%@",[userdefaults objectforkey:@"name"]);
    nslog(@"%@",[userdefaults objectforkey:@"sex"]);
    nslog(@"%@",[userdefaults objectforkey:@"work"]);

三. 归档与解档

(一). 知识点

归档又名序列化,把对象转为字节码,以文件的形式存储到磁盘上;程序运行过程中或者重新打开程序时,可以通过解归档(反序列化)还原这些对象。 不是所有的对象都可以直接用这种方法进行归档,只有遵守了nscoding协议的对象才可以,如果对象是nsstring、nsdictionary、nsarray、nsdata、nsnumber等类型,可以直接用nskeyedarchiver进行归档。 每次归档对象时,都会调用encodewithcoder:方法;一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeobject:forkey:方法归档实例变量。 每次从文件中恢复(解码)对象时,都会调用initwithcoder:方法;一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeobject:forkey方法解码实例变量。 归档和解归档可以用于少量数据的持久化存储和读取,且通过归档创建的文件是的

缺点:在归档的形式来保存数据,只能一次性归档保存以及一次性解压,所以只能针对小量数据。而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据。

(二). 具体使用

归档方式有以下三种:
a. 对foundation框架中对象进行归档
b. 对自定义的内容进行归档
c. 对自定义的对象进行归档

1. 对foundation框架中对象进行归档

    // 获取文件路径
    nsstring *documentspath = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes)[0];
    // 拼接路径
    nsstring *datapath = [documentspath stringbyappendingpathcomponent:@"newdata.data"];

    // 待归档的数据
    nsarray *dataarr = @[@"天天",@"编程"];

    // 归档
    if ([nskeyedarchiver archiverootobject:dataarr tofile:datapath]) {
        nslog(@"archiver success !");
    }

    // 解档
    nsarray *data = [nskeyedunarchiver unarchiveobjectwithfile:datapath];

    nslog(@"%@%@",data[0],data[1]);

2. 对自定义的内容进行归档

    // 获取文件路径
    nsstring *documentspath = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes)[0];
    // 拼接路径
    nsstring *datapath = [documentspath stringbyappendingpathcomponent:@"newdata.data"];

    // 创建存储数据的nsdata对象
    nsmutabledata *datam = [nsmutabledata data];

    // 创建归档对象
    nskeyedarchiver *archiver = [[nskeyedarchiver alloc] initforwritingwithmutabledata:datam];

    // 添加归档内容
    [archiver encodeobject:@"小明" forkey:@"name"];
    [archiver encodeobject:@"男" forkey:@"sex"];
    [archiver encodeinteger:19 forkey:@"age"];

    // 完成归档内容
    [archiver finishencoding];

    // 写入磁盘
    if ([datam writetofile:datapath atomically:yes]) {
        nslog(@"archiver success !");
    }


    // 解档
    // 获取数据
    nsdata *data = [nsdata datawithcontentsoffile:datapath];

    // 创建解档对象
    nskeyedunarchiver *unarchiver = [[nskeyedunarchiver alloc] initforreadingwithdata:data];

    // 解档
    nsstring *name = [unarchiver decodeobjectforkey:@"name"];
    nsstring *sex = [unarchiver decodeobjectforkey:@"sex"];
    nsinteger age = [unarchiver decodeintforkey:@"age"];


    nslog(@"%@  %@  %ld",name,sex,age);

3. 对自定义的对象进行归档

---------- person.h 文件

#import 

@interface person : nsobject 

@property (nonatomic,strong) nsstring *name;

@property (nonatomic,strong) nsstring *sex;

@property (nonatomic,assign) nsinteger age;

@end

---------- person.m 文件

#import "person.h"

@implementation person 

// 归档
- (void)encodewithcoder:(nscoder *)acoder {
    [acoder encodeobject:self.name forkey:@"name"];
    [acoder encodeobject:self.sex forkey:@"sex"];
    [acoder encodeinteger:self.age forkey:@"age"];
}

// 解档
- (instancetype)initwithcoder:(nscoder *)adecoder {

    if (self = [super init]) {
        self.name = [adecoder decodeobjectforkey:@"name"];
        self.sex = [adecoder decodeobjectforkey:@"sex"];
        self.age = [adecoder decodeintegerforkey:@"age"];

    }
    return self;
}

@end

---------- 对penson对象进行归档与解档

    // 获取documents的路径
    nsstring *documentpath = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes).firstobject;
    // 拼接路径
    nsstring *path = [documentpath stringbyappendingpathcomponent:@"person.data"];

    //
    person *per = [[person alloc] init];
    per.name = @"xiaoming";
    per.sex = @"男";
    per.age = 20;

    // 归档
    [nskeyedarchiver archiverootobject:per tofile:path];

    // 解档
    person *person = [nskeyedunarchiver unarchiveobjectwithfile:path];

    nslog(@"%@",person.sex);