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前往文件夹中就可以看到沙盒中如下结构

iOS数据持久化学习笔记(一)_第1张图片
图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
iOS数据持久化学习笔记(一)_第2张图片
图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。。。来保存数据的
一般有以下几种方式


iOS数据持久化学习笔记(一)_第3张图片
图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 
//定义了三个属性
@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 

@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”文件

iOS数据持久化学习笔记(一)_第4张图片
图5.png

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


iOS数据持久化学习笔记(一)_第5张图片
图6.png

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

你可能感兴趣的:(iOS数据持久化学习笔记(一))