iOS数据持久化学习笔记(一)

最近在学习在iOS开发中如何做数据的持久化。我们在开发APP时有时需要将数据保存到本地。下面总结一下几种数据持久化的方式及其应用。这只是我的学习笔记,有错误的地方还望指点。
数据持久化的几种方式:
a.XML属性列表(plist)
b.Preference(偏好设置)
c.NSKeyedArchiver归档(NSCoding)
d.SQLite
e.Core Data
这篇笔记先总结一下前三种(plist、偏好设置、归档)。后面两种(SQLite、Core Data)在下篇总结。在介绍之前先了解一下沙盒(sandbox)结构。

我们通过如下代码:

NSString *homePath = NSHomeDirectory();
NSLog(@"%@",homePath);

可以获取到沙盒路径。
然后将路径贴到Finder前往文件夹中就可以看到沙盒中如下结构

图1.png

Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录,还有我们的通讯录之类的。
Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据。比如我们朋友圈缓存的照片。
Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录。比如我们设置的字体、皮肤、账户信息等。
tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录。

1.路径获取
(1) Documents
方式1:

documenstPath = [homePath stringByAppendingPathComponent:@"Documents"];

方式2:

 documenstPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

(2) 获取Caches路径

NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];   
//参数:YES:全路径  NO:相对路径

注:Preference路径不能用搜索的方式去获取,可以通过拼接路径获取到,但是苹果不希望我们这样做。

要使用偏好设置,是这样获取得的

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

(3) 获取tmp路径

NSString *tmpPath = NSTemporaryDirectory();

2.plist的使用

图2.png
图3.png

plist文件保存数组

// 1.创建数组 
NSArray *array = @[@"1",@"2",@"3"];

// 2.获取Documents路径 沙盒/Documents 
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
// 3.拼接文件路径  沙盒/Documents/array.plist
NSString *filePath = [documents stringByAppendingPathComponent:@"array.plist"];
    
// 4.写入文件
BOOL success = [array writeToFile:filePath atomically:YES];
//atomically:线性安全的

读取保存好的数组

 // 1.获取documents路径
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];  
//2.拼接文件路径
NSString *filePath = [documents stringByAppendingPathComponent:@"array.plist"];
    
 // 2.读取数组
NSArray *array = [NSArray arrayWithContentsOfFile:filePath];

plist文件保存字典

// 1.创建字典
NSDictionary *dict = @{@"a":@"1",@"b":@"2",@"c":@"3"};
    
// 2.获取Documents路径 沙盒/Documents
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
// 3.拼接文件路径  沙盒/Documents/dict.plist
NSString *filePath = [documents stringByAppendingPathComponent:@"dict.plist"];
    
// 4.写入文件
[dict writeToFile:filePath atomically:YES];

读取保存好的字典

// 1.获取documents路径
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

//2.拼接文件路径
NSString *filePath = [documents stringByAppendingPathComponent:@"dict.plist"];
    
// 3.读取字典
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];

2.Preference(偏好设置)

// 1.获取偏好设置 default/standard/share/main
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
// 2.保存数据
[defaults setObject:@"仰望星空" forKey:@"name"];
[defaults setBool:YES forKey:@"boy"];
    
// 3.读取数据
NSString *name = [defaults objectForKey:@"name"];
BOOL sex = [defaults boolForKey:@"boy"];
    
NSLog(@"%@ %@",name,sex?@"YES":@"NO");
    
// iOS8之前 需要同步
[defaults synchronize];

Preference(偏好设置) 是通过 set 。。。forKey。。。来保存数据的
一般有以下几种方式


图4.png

读取也是通过相应的方法来读取
[defaults objectForKey:@"name"];
[defaults boolForKey:@"boy"];

3.NSKeyedArchiver归档(NSCoding)
在iOS开发中,经常需要保持一些对象,属性列表和偏好设置均不能实现。针对这种情况,iOS提供了对象归档技术。它采用序列化的方式,实现对象的存储。通常来说对象归档的操作有两个方面。具体如下:
对象归档:以一种不可读的方式,将对象写入到指定文件中。
对象反归档:从指定文件中读取数据,并自动的重建对象。
对于这两种情况,iOS提供了相应的类,实现对象的归档和反归档,具体如下:
1.NSKeyedArchiver 类
NSKeyedArchiver 类直接继承NSCoder类,将对象归档到指定的文件中,该类提供了两个方法。

+ (NSData *)archivedDataWithRootObject:(id)rootObject;
+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;

均是类方法无需创建对象,直接使用类名NSKeyedArchiver 调用就可以了。其中 archiveRootObject 方法需要传入一个路径参数,该参数用于指定对象保存路径。

2.NSKeyedUnarchiver 类
NSKeyedUnarchiver 类也是直接继承NSCoder类,负责从文件中回复对象,该类提供了两个方法,具体格式如下:

+ (nullable id)unarchiveObjectWithData:(NSData *)data;
+ (nullable id)unarchiveObjectWithFile:(NSString *)path;

unarchiveObjectWithFile 方法也是需要传入一个路径参数。

NSCoding协议
在对象的归档技术中,如果对象要归档需要遵守NSCoding协议,凡是遵守了NSCoding协议的自定义对象,都可以实现对象的归档和反归档。NSCoding协议中定义了两个方法,这两个方法是对象归档必须实现的。

- (void)encodeWithCoder:(NSCoder *)aCoder; //该方法负责归档该对象的所有是咧变量
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;  //该方法负责恢复该对象的实例变量的值

所以通过重写这两个方法,来指定如何归档和回复对象的每个实例变量,为此,NSCoder类提供了相应的方法来实现对象的归档、恢复对象每个实例变量的方法。

常用的归档数据的方法

- (void)encodeObject:(nullable id)objv forKey:(NSString *)key;  //将Object类型编码,使其与字符串类型的键相关联
- (void)encodeBool:(BOOL)boolv forKey:(NSString *)key;  //将BOOL类型编码,使其与字符串类型的键相关联
- (void)encodeInt:(int)intv forKey:(NSString *)key;  //将int类型编码,使其与字符串类型的键相关联
- (void)encodeFloat:(float)realv forKey:(NSString *)key;  //将float类型编码,使其与字符串类型的键相关联
- (void)encodeDouble:(double)realv forKey:(NSString *)key;  //将double类型编码,使其与字符串类型的键相关联

常用的恢复对象实例变量的方法

- (nullable id)decodeObjectForKey:(NSString *)key;  //解码并返回一个与给定键相关联的Object类型的值
- (BOOL)decodeBoolForKey:(NSString *)key;  //解码并返回一个与给定键相关联的Bool类型的值
- (int)decodeIntForKey:(NSString *)key;  //解码并返回一个与给定键相关联的int类型的值
- (float)decodeFloatForKey:(NSString *)key;  //解码并返回一个与给定键相关联的float类型的值
- (double)decodeDoubleForKey:(NSString *)key;  //解码并返回一个与给定键相关联的double类型的值

使用归档保存对象,应用如下:
我们创建一个Person类
Person.h文件中

@interface Person : NSObject <NSCoding>
//定义了三个属性
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) float height;

@end

Person.m文件中

#import "Person.h"
@implementation Person
//将一个自定义归档时就会调用该方法,该方法用于描述如何存储自定义对象的属性
-(void)encodeWithCoder:(NSCoder *)aCoder{
    
    [aCoder encodeObject:self.name forKey:@"Name"];
    [aCoder encodeInt:self.age forKey:@"Age"];
    [aCoder encodeFloat:self.height forKey:@"Height"];
}

//从文件读取一个对象的时候会调用该方法,该方法用于描述如何读取保存在文件中的数据
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        
        self.name = [aDecoder decodeObjectForKey:@"Name"];
        self.age  = [aDecoder decodeIntForKey:@"Age"];
        self.height = [aDecoder decodeFloatForKey:@"Height"];
    }
    return self;
}

//重写description方法,打印对象的时候,就可以将其所有属性打印出来
-(NSString *)description{
    return [NSString stringWithFormat:@"name = %@, age = %d height = %0.1f",_name,_age,_height];
}

ViewController.h 文件中

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

ViewController.m 文件中

#import "ViewController.h"
#import "Person.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

//单击“保存”按钮执行的方法
-(IBAction)save{
    
    //1.创建对象
    Person *person = [[Person alloc]init];
    person.name = @"Rose";
    person.age = 18;
    person.height = 48;
    
    //2.获取 Documents 路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    //3.拼接将要保存文件的路径,文件名可以随便取 后缀也可以随便给
    NSString *filePath = [path stringByAppendingPathComponent:@"person.data"];
    
    // NSLog(@"%@",filePath);
    
    //4.将对象 person 归档
    [NSKeyedArchiver archiveRootObject:person toFile:filePath];
    
}

//单击“读取”按钮执行的方法
-(IBAction)read{
    
    //1.获取 Documents 路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    
    //2.拼接保存的文件路径
    NSString *filePath = [path stringByAppendingPathComponent:@"person.data"];
    
    //3.从指定的文件中读取对象
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    
    NSLog(@"%@",person);
    
}

@end

点击“保存”按钮后,Documents 文件家中出现了“person.data”文件

图5.png

点击“读取”按钮后,成功打印了person 对象属性,说明保存和读取数据都是成功的。


图6.png

数据持久化的前三种方式(plist、偏好设置、归档)总结完了,后面两种(SQLite、Core Data)将在下篇总结。

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

推荐阅读更多精彩内容