iOS之本地存储的几种方式

前言

作为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进去,点击前往按钮
可以在模拟器下查看沙盒文件,如下图:

test_plist.png

读取刚存储的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同步设备时会备份该目录
  • 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

你可能感兴趣的:(iOS之本地存储的几种方式)