爬爬爬之路:UI(十六) 数据持久化初级(沙盒实现)

沙盒机制

沙盒是什么?

iOS应用在运行的时候, 系统会自动为其开辟一个独立的区域, 通常生成3个文件夹用于存放应用的非代码文件, 存放的内容包括图像, 图标, 声音, 视屏, 文本文件等等等等. 这块区域就称为沙盒.

沙盒机制

  1. 每个应用程序都会自动生成3个文件夹, 分别是Documents, Library, tmp.
  2. 每个应用程序的沙盒是互相独立的, 无法在一个应用程序中访问另一个应用程序的沙盒.
  3. 每个应用程序的沙盒存放的是代码以外的所有数据. 例如(图片素材 声音 视频 文档等等)

沙盒的特性

对于应用而言, 每一次运行都是一个重新安装的过程. 而当每个应用程序运行的时候, 系统都会随机在目录下生成一个文件夹, 其文件夹名是随机生成的. 即使是同一个应用程序, 每次运行的时候依然会生成和上一次运行生成的文件夹不同的文件夹. 但是会把上一次运行时生成的文件夹中的内容转移到本次生成的文件夹中, 并且会删除上一次运行生成的文件夹.

沙盒在首次运行时, 系统默认的情况下会生成3个文件夹, 分别是Documents, Library, tmp
其中tmp文件夹的内容在每次开机时都会被清除, 或者在手机开机的状态下, 系统提示内存不足的时候, 也有几率删除tmp文件夹的内容.
而Documents和Library文件夹中的内容是可以被备份的.


沙盒地址的获取方法

获取沙盒主路径的方法

NSString *appPath = NSHomeDirectory();
利用一个函数, 可以随时随地不受限制的获取当前运行状态下的沙盒主目录.

沙盒内容介绍

Documents文件夹

Documents文件夹通常用于保存用户的一些文档数据等需要永久保留的文件.

获取Documents文件夹目录的方法
NSArray *documents = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentPath = [documents firstObject];

// 利用函数可以获取Documents文件夹的路径
// 函数的第一个参数为目标文件夹的目录名
// 还可以填写NSLibraryDirectory NSCachesDirectory等, 根据不同的值 可以获取不同文件夹的路径
// 第二个参数为搜索范围
// NSUserDomainMask为搜索User目录下的内容 通常填写此参数即可
// 第三个参数是用于控制是否获取全路径, 若填NO, 会自动隐藏主目录用'~'代替
// NSSearchPathForDirectoriesInDomains()函数的作用根据需求是返回指定目录的路径, 若该路径下的文件有多个, 则返回的数组中元素有多个, 若只有一个文件夹, 则返回数组中的元素个数为1. 由于Documents的文件夹只有一个, 所以用[documents firstObject], [documents lastObject], documents[0]取得路径均可

Library文件夹

Library文件夹下分文两个文件夹Caches和Preferences两个文件
Caches主要存放的是系统缓存文件
Preferences主要存放的是系统配置文件

获得Library文件夹路径的方法
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
获得Library文件夹下Caches文件夹路径的方法
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory , NSUserDomainMask, YES) firstObject];

获得tmp文件夹路径的方法

NSString *tmpPath = NSTemporaryDirectory();

简单对象写入沙盒

简单对象: 系统类实力出来的对象, 都是简单对象
例如 字符串, 数组, 字典, 二进制对象(NSData)
注意, 数组, 字典里面也只能存放简单对象.

字符串的写入

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error;

// 第一个参数 保护写入作用, 若YES在写入过程中出现意外情况 也可以写入成功. 做法是先将数据写入内存中 再写到硬盘里. NO为不保护, 也就是直接写入硬盘中, 若发生意外会导致写入失败.
// 第二个参数 编码格式 使用UTF-8格式 NSUTF8StringEncoding
// 第三个参数 不需要查看错误信息的时候填nil即可

// 字典 数组 对象的写入方法同NSString对象

数组数据的读取

NSString *arrayPath = [kDocumentPath stringByAppendingPathComponent:@"/shuzu.plist"];

NSArray *array = [NSArray arrayWithContentsOfFile:arrayPath];

// 字典读取同数组

将图片转化成data类型写入

// 注意图片得是png格式的
NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:@"people"]);
NSString *dataPath = [kDocumentPath stringByAppendingPathComponent:@"/data"];
[imageData writeToFile:dataPath atomically:YES];

文件管理类

文件管理类(NSFileManager)是用来管理文件夹的类, 并不是直接管理具体文件的类.

作用是可以对文件夹进行创建 移动 复制 删除操作.

创建文件管理类

NSFileManager *manager = [NSFileManager default]
// 文件管理类的文件夹路径的最后一个路径是指定的文件夹名

创建文件夹

- (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error;
// 第一个参数是文件夹的路径
// 第二个参数是当所创的文件已存在同名文件的情况 是否覆盖  否 则创建失败
// 第三个参数设置文件的属性 比如隐藏 等等 通常nil就行

根据路径移动文件夹到新路劲下

- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
// 第一个参数是旧的文件夹路径
// 第二个参数是新的文件夹路径
// 如果旧的文件夹路径还有其他文件夹或者文件  会一同被移动到新的路径下 移动的前提是文件夹存在
// 移动的结果是原文件夹的内容被剪切到新的文件夹路径下
// 新文件夹名和旧文件夹名可以不相同

根据路径复制文件夹到新的路径下

- (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
// 复制的结果是原文件夹依然存在, 新文件夹的文件名和旧文件夹名可以不同.

根据路径删除文件夹

- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error;

判断路径下的文件夹是否存在

- (BOOL)isExecutableFileAtPath:(NSString *)path;

复杂对象的存储
复杂对象: 自己创建出来的类(例如 Student类)
写入的核心思想:
把复杂对象 转化成 简单对象 进行写入
一般转化成 NSData 对象进行写入

简单对象和复杂对象的区别, 简单对象有writeToFile方法, 但是更本质的原因是因为他们遵守了NSSecureCoding这个协议 而这个协议的本质是因为遵守了NSCoding协议

复杂对象的写入步骤:

第一步 需要存储的对象的类遵守NSCoding协议 (需要在写入的时候 按照一定的规则 也就是编码格式 写入)

NSCoding协议定义两个方法如下:

// 归档 (序列)  写入的格式
- (void)encodeWithCoder:(NSCoder *)aCoder;

// 反归档 (反序列)   读取的格式
- (id)initWithCoder:(NSCoder *)aDecoder;

第二步 重写(协议中的)归档与反归档方法

// 归档
- (void)encodeWithCoder:(NSCoder *)aCoder {

    // 按照一定编码格式
    // 将类中的所有属性进行归档
    // 注意1: 归档时候key要与 反归档时的key一致
    // 注意2: 归档要选用与属性类型一致的编码方法
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInteger:self.age forKey:@"age"];
    // data可以使用对象类型 也可以使用encodeDataObject: 在反归档的时候需要用其对应的方法取, 当时一般统一使用encodeObject:forKey:
//    [aCoder encodeDataObject:self.imageData];
    [aCoder encodeObject:self.imageData forKey:@"imageData"];
}

// 反归档
- (id)initWithCoder:(NSCoder *)aDecoder {
//    Student *student = [[Student alloc] init];
    self = [super init];
    if (self) {
        // 按照一定编码格式 和 存储的key标识 取出被归档的对象(反归档)
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];
        self.imageData = [aDecoder decodeObjectForKey:@"imageData"];
    }
    return self;
}

步骤三 创建复杂对象

NSData *imagedata = UIImagePNGRepresentation([UIImage imageNamed:@"people"]);
Student *student = [[Student alloc] init];
student.name = @"一个人";
student.age = 18;
student.imageData = imagedata;

步骤四 创建归档对象 并利用归档对象把复杂对象转化成简单对象data

// 创建一个可变data
NSMutableData *data = [NSMutableData data];
// 创建一个归档对象
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
// 将复杂对象 通过归档对象 转化成data
[archiver encodeObject:student forKey:@"student"];
// 完成归档 (注意别漏了这一步)
[archiver finishEncoding];
// 实际上 通过 归档对象 把 复杂对象 写入data
// 归档反归档不是数据持久化
// 只是把复杂对象 按照系统编码的格式 写入data
// 真正数据持久化 还是 写入文件中
//    NSLog(@"%@", data);

第五步 把data写入文件 进行数据持久化

// 1. 获取路径  2. 拼接路径(为了给文件起名)  3. 写入数据
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *path = [documentPath stringByAppendingPathComponent:@"/Student"];
[data writeToFile:path atomically:YES];
// 释放归档对象
NSLog(@"%@", path);
[archiver release];

第六步 创建反归档对象, 根据反归档对象获取data 并将data反归档成复杂对象

// 反归档
// 从沙盒中 读取data数据
NSData *studentData = [NSData dataWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:studentData];
Student *stu = [unarchiver decodeObjectForKey:@"student"];
[unarchiver finishDecoding];
[unarchiver release];
NSLog(@"%@", stu.name);
NSLog(@"%ld", stu.age);
NSLog(@"%@", stu.imageData);
UIImage *image = [UIImage imageWithData:stu.imageData];

如何把一个数组的复杂对象 写到文件中

遍历数组, 把每一个复杂对象 转化成简单对象(NSData), 然后再将data保存到一个数组中 最后把这个数组直接写入到文件中进行持久化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值