前言
作为iOS开发工程师,所需要的数据几乎全部都是通过网络获取,而且网络请求都有时耗;在网络好的情况下这种时耗虽然不足考虑,但是一旦网络环境不好,会很影响产品体验。网络环境无法控制,但是对于一些数据不经常变动的网络请求或没必要实时更新的数据,我们可以选择将网络数据缓存本地,适时更新,还有一些做视频、音乐app,音乐和视频难免要存储到本地。
常见的存储方式
- plist文件存储
- NSUserDefaults(Preference偏好设置)
- 归档
- 沙盒存储
- 数据库存储
plist文件
- plist文件(属性列表存储)
- 可以存储的类型:
- Array
- Dictionary
- String
- Boolean
- Date
- Data
- Number
- 用途:
- 储存用户的设置
- 存储项目中经常用到又不经常修改的数据
- 不适合存储大量数据,而且只能存储基本数据类型。
- 虽然可以实现 :增 删 改 查 等操作,但由于数据的存取必须是一次性全部操作,所以性能方面表现并不好
实际应用,如下代码:
NSDictionary *dict = @{
@"name":@"zhangsan",
@"age" : @(18),
};
//获取documenth路径
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
//在document路径下创建一个test.plist文件
NSString *filePath = [documentPath stringByAppendingPathComponent:@"test.plist"];
//写入数据
[dict writeToFile:filePath atomically:YES];
可以打印一下filePath的路径:
NSLog(@"filePath = %@", filePath);
打印结果如下:
filePath = /Users/ypf/Library/Developer/CoreSimulator/Devices/FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/475B1C5E-5C98-4423-92B9-653CC5C9A249/Documents
然后在通过打开 访达-》前往 -》 前往文件夹,把打印的filePath路径copy进去,点击前往按钮
可以在模拟器下查看沙盒文件,如下图:
读取刚存储的plist数据:
//获取documenth路径
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
//在document路径下创建一个test.plist文件
NSString *filePath = [documentPath stringByAppendingPathComponent:@"test.plist"];
//读取test.plist数据
NSDictionary *listDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSLog(@"listDict -- %@",listDict);
查看一下打印结果:
listDict -- {
age = 18;
name = zhangsan;
}
对其参数进行解读:
NSDocumentDirectory:第一个参数代表要查找哪个文件,是一个枚举。
表示搜索的范围限制于当前应用的沙盒目录
YES (expandTilde): 第三个参数是一个BOOL值。iOS中主目录的全写形式是/User/userName,这个参数填YES就表示全写,填NO就是写成‘‘~’’
NSUserDefaults
应用程序启动后,会在沙盒路径Library -> Preferences 下默认生成以工程bundle为名字的 .plist 文件 , 该方式存储的数据即存进该文件当中。
用途:
- 常用于存储用户的个人偏好设置
- 这种方式本质是操作plist文件,所以性能方面的考虑同plist文件数据储存。
沙盒存储
沙盒路径下有三个文件:
-
Documents
- 保存应用运行时生成的需要持久化的数据
- iTunes同步设备时会备份该目录。(例如,游戏应用可将游戏存档保存在该目录)
-
Library 中包含两个文件夹
- Caches
- 保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。
- 一般存储体积大、不需要备份的非重要数据
- Preferences
- 保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。
- iTunes同步设备时会备份该目录
- Caches
-
temp
保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。
应用没有运行时,系统也可能会清除该目录下的文件。
iTunes同步设备时不会备份该目录
获取沙盒路径
// 获取沙盒的路径
NSString *homePath = NSHomeDirectory();
获取 Documents 路径
//第一种写法通过NSDocumentDirectory直接获取
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [docPaths lastObject];
NSLog(@"documentsPath : %@", documentsPath);
//通过沙盒拼接获取
NSString *sandPath = NSHomeDirectory();
NSString *docPath = [sandPath stringByAppendingPathComponent:@"Documents"];
NSLog(@"docPath :%@", documentsPath);
documentsPath、docPath打印结果是一样的:
documentsPath :/Users/ypf/Library/Developer/CoreSimulator/Devices/
FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/
A7DF470C-1037-4C42-B0E1-5A7B5B85D540/Documents
docPath :/Users/ypf/Library/Developer/CoreSimulator/Devices/
FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/
A7DF470C-1037-4C42-B0E1-5A7B5B85D540/Documents
获取Library/Caches
//第一种通过NSCachesDirectory直接获取
NSArray *cachesPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [cachesPaths lastObject];
NSLog(@"cachePath :%@", cachePath);
//沙盒路径拼接获取
NSString *sandPath = NSHomeDirectory();
//拼接上Caches路径
NSString *docPath = [sandPath stringByAppendingPathComponent:@"Library/Caches"];
NSLog(@"cachePath1 :%@", docPath);
打印结果:
cachePath :/Users/ypf/Library/Developer/CoreSimulator/Devices/FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/775D95B6-A708-42DF-B9E1-54F428055A4B/Library/Caches
cachePath1 :/Users/ypf/Library/Developer/CoreSimulator/Devices/FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/775D95B6-A708-42DF-B9E1-54F428055A4B/Library/Caches
获取Library/Perferences
使用NSUserDefault来保存的数据都存在这个文件夹下,格式是plist
获取temp路径
//第一种直接获取temp路径
NSString *tmpPath = NSTemporaryDirectory();
NSLog(@"tmpPath -- %@",tmpPath);
//通过沙盒拼接路径
NSString *sandPath = NSHomeDirectory();
NSString *tmpPath1 = [sandPath stringByAppendingPathComponent:@"tmp/"];
NSLog(@"tmpPath1 -- %@",tmpPath1);
打印结果如下:
tmpPath -- /Users/ypf/Library/Developer/CoreSimulator/Devices/FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/F54C0641-B375-481B-AA51-C9E42031B3AC/tmp/
tmpPath1 -- /Users/ypf/Library/Developer/CoreSimulator/Devices/FDD9E566-4F59-41FB-89BA-D9BCEBB133EA/data/Containers/Data/Application/F54C0641-B375-481B-AA51-C9E42031B3AC/tmp/
沙盒主要作用就是文件存储:
文件操作可通过单例 NSFileManager 处理。文件存储的路径可以代码设置。
可以存储大量数据,对数据格式没有限制。
但由于数据的存取必须是一次性全部操作,所以在频繁操作数据方面性能欠缺。
归档和解档
plist 与 NSUserDefaults(个人偏好设置)两种类型的储存只适用于系统自带的一些常用类型,而且前者必须拿到文件路径,后者也只能储存应用的主要信息。要是存储对象的话需要归档和解档
注意:
-
值得注意的是使用归档保存的自定义模型需要实现NSCoding协议下的两个方法:
-
- (void)encodeWithCoder:(NSCoder *)aCoder(归档时调用这个方法)
-
- (instancetype)initWithCoder:(NSCoder *)aDecoder(解档时调用这个方法)
-
代码如下:
Person.h
#import
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
NS_ASSUME_NONNULL_END
#import "Person.h"
@implementation Person
//接档
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
@end
用归档存储对象:
//获取documents路径
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
NSString *filePath = [documentPath stringByAppendingPathComponent:@"ArchievrModel"];
Person *person = [Person new];
person.age = 25;
person.name = @"张三";
//归档存入数据
[NSKeyedArchiver archiveRootObject:person toFile:filePath];
//解档获取数据
Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"name -- %@, age -- %ld ",p.name,p.age);
打印结果:
name -- 张三, age -- 25
数据库存储
数据存储使用的SQLite:
它是一款轻型的嵌入式数据库,安卓和ios开发使用的都是SQLite数据库
占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了
它的处理速度比Mysql、PostgreSQL这两款著名的数据库都还快。
FMDB 正式基于 SQLite 开发的一套开源库。使用时,需要自己写一些简单的SQLite语句
。
CoreData 是苹果给出的一套基于 SQLite 的数据存储方案.
不需要自己写任何SQLite语句
该功能依赖于 CoreData.framework 框架,该框架已经很好地将数据库表和字段封装成了对象和属性,表之间的一对多、多对多关系则封装成了对象之间的包含关系。
Core Data的强大之处就在于这种关系可以在一个对象更新时,其关联的对象也会随着更新,相当于你更新一张表的时候,其关联的其他表也会随着更新。
Core Data的另外一个特点就是提供了更简单的性能管理机制,仅提供几个类就可以管理整个数据库
由于直接使用苹果提供的CoreData容易出错,这里提供一个很好的三方库 MagicalRecord 。
总结
接口数据缓存存储方式:
-
文件读写
- 大部分接口数据解析之后写入文件保存(读写操作最好 GCD 子线程操作)
-
归档
- 整个应用需要用到的重要数据模型可以考虑采用归档方式(标记状态的数据模型)
-
个人偏好设置(NSUserDefaults)
- 与用户相关的信息、单个标记标识等采用个人偏好设置。
当然对于一些涉及查询、删除、更新等操作的数据模型,就需要使用数据库操作。
使用FMDB写一些SQL语句来执行
推荐使用 CoreData 的封装库 MagicalRecord