iOS 一一 数据存储

iOS应用数据存储的常用方式

  • XML属性列表(plist) 归档
  • Preference(偏好设置)
  • NSKeyedArchiver归档(NSCoding)
  • SQLine3
  • Core Data

本篇博客只介绍前三种存储的常用方式.后两种后续会继续更新.


在讲述iOS数据存储之前.首先要了解什么是应用沙盒,以及沙盒中的目录结构.


应用沙盒

  • 每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录). 与其他文件系统隔离.应用必须待在自己的沙盒中,其他应用不可以访问该沙盒
  • 应用沙盒的文件系统目录.如下


注意:

我们可以通过NSLog(@"%@",NSHomeDirectory)来打印 应用程序沙盒的根目录


接下来针对以上目录,一一说明其有什么作用:

  • Documents: 保存应用运行时生成的需要持久化数据,iTunes同步设备时会备份该目录.

注意: 在Documents目录中不可以存放一些网络中下载的比较大的数据,因为iTunes会备份,如果存放一些比较大的数据,当应用程序打包上传appStore 会被审核不通过.

Documents目录 一般存放一些应用程序生成的一些数据


  • tmp: 保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除.应用程序没有运行时,系统可能会清除该目录下的文件.iTunes同步设备时不会备份该目录

  • Library/Caches: 保存应用运行时生成的需要持久化的数据,iTunes同步设备不会备份该目录.一般存储体积大、不需要备份的非重要的数据
注意:从网络中下载比较大的数据一般都放在Library/Caches目录下.

Library/Preference: 保存应用的所有偏好设置.iOS的应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录


应用沙盒目录的获取方式.

Plist存储:

plist 件存储 般都是存取字典和数组,直接写成plist 件,把它存到应 沙盒当

中.只有在ios当中才有plist存储,它是ios特有的存储 式. 

介绍完沙盒中的目录后.来讲解一下如何获取沙盒中的目录.

  • 沙盒的根目录: NSString *path = NSHomeDirectory();
比如要获取沙盒中Documents目录:
利用NSSearchPathForDirectoriesInDomains方法,这个方法返回是一个数组

iOS中,只有一个目录跟传入的参数匹配,所以这个集合里面只有一个元素

这个方法的参数:

arg1: NSDocumentDirectory 找到沙盒中目录(NSDocument,Caches)

arg2: NSUserDomainMask 搜索的范围(一般写NSUserDomainMask,沙盒的固定范围)

arg3: 是否展开路径(YES) 注: 在iOS开发中不识别~,在Mac平台可识别,所以必须要展开路径

NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];

在Documents目录下拼接一个文件名:

NSString *filePath = [path stringByAppendingPathComponent:@"data.plist"];

把字典数据保存到沙盒目录下的data.plist文件中

NSDictionary *dictArray = @{@"name" : @"ZY"};
[dictArray writeToFile: filePath atomically: YES];

在这里.可以打印一下path,进入到沙盒的Documents目录下的data.plist文件中.数据是否已经保存在里面.



从沙盒目录下的文件中读取数据:

需要使用到dictionaryWithContentsOfFile:方法

    // 读取沙盒目录中的字典文件
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    // 拿到字典文件名称
    NSString *filePath = [path stringByAppendingPathComponent:@"data.plist"];
    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"%@",dict);


属性列表:

  • 属性列表是一种XML格式的文件,拓展名为plist
  • 如果对象是NSStringNSDictionaryNSArrayNSDataNSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中



Prference(偏好设置)
  • 许多iOS应用都支持偏好设置,比如保存用户名,密码,字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能.
  • 每个应用都有NSUserDefaults实例,通过它来存储偏好设置
  • 比如 保存用户名,字体大小,是否自动登录
  • 注意: NSUserDefaults 保存的也是一个plist文件

保存数据到沙盒中

    // Preferences 保存在library/Preferences目录中(plist文件)
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:@"ZY" forKey:@"name"];
    [defaults setInteger:19 forKey:@"age"];
    
    // 立刻写入到文件中(同步操作)
    [defaults synchronize];
    
    NSLog(@"%@",NSHomeDirectory());


从沙盒中读取数据

    // 读取
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    // 根据key去取值
    NSString *name = [defaults objectForKey:@"name"];
    NSLog(@"%@",name);
    
    NSInteger integer = [defaults integerForKey:@"age"];
    NSLog(@"%ld",integer);


归档:

归档一般都是保存自定义对象的时候,使用归档.因为plist文件不能保存自定义对象.

如果一个字典当中保存有自定义对象,如果把这个字典写入到文件中,不会生产plist文件.


写入到沙盒的tmp目录下

archiveRootObject会调用encodeWithCode: 方法

Person *person = [[Person alloc] init];
    person.name = @"ZY";
    person.age = 19;
    
    Dog *dog = [[Dog alloc] init];
    dog.name = @"wangcai";
    
    person.dog = dog;
    
    // 获取沙盒中的指定目录(tmp目录)
    NSString *path = NSTemporaryDirectory();
    NSLog(@"%@",path);
    // 拼接文件名称
    NSString *filePath = [path stringByAppendingPathComponent:@"person.data"];
    
    // 归档(会调用encodeWithCoder方法) 把对象保存到沙盒的指定目录中
    [NSKeyedArchiver archiveRootObject:person toFile:filePath];


unarchiveObjectWithFile会调用 initWithCoder 方法

    // 接档操作
    NSString *path = NSTemporaryDirectory();
    NSString *filePath = [path stringByAppendingPathComponent:@"person.data"];
    
    // 解档(什么类型,会调用initWithCoder: 方法)
   Person *per =  [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
   NSLog(@"%@--%@",per.name,per.dog.name);

Person文件

#import <Foundation/Foundation.h>
@class Dog;
@interface Person : NSObject<NSCoding>

/** 姓名 */
@property(nonatomic,strong)NSString * name;

/** 年龄 */
@property(nonatomic,assign)int age;

/** 狗 */
@property(nonatomic,strong)Dog * dog;

@end

@implementation Person

// 保存当前对象的哪些属性
//- (void)encodeWithCoder:(NSCoder *)aCoder
//{
//    [aCoder encodeObject:self.name forKey:@"name"];
//    [aCoder encodeInt:self.age forKey:@"age"];
//}
//
 当解析一个文件的时候调用.(告诉当前要解析文件当中哪些属性)
//- (instancetype)initWithCoder:(NSCoder *)aDecoder
//{
//    if (self = [super init]) {
//        self.name = [aDecoder decodeObjectForKey:@"name"];
//        self.age = [aDecoder decodeIntForKey:@"age"];
//    }
//    
//    return self;
//}

// 保存当前对象的哪些属性到沙盒中
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInt:self.age forKey:@"age"];
    [aCoder encodeObject:self.dog forKey:@"dog"];

}

// 当解析一个文件的时候调用(告诉当前要解析文件当中的哪些属性)
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    // 如果父类也准守了<NSCoding>协议,就可以调用initWithCoder:方法
    if (self = [super init]) {
        // 需要解析文件中哪些属性
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntForKey:@"age"];
        self.dog = [aDecoder decodeObjectForKey:@"dog"];
    }
    return self;
}

@end

NSKeyedArchiver-归档对象的注意

  • 如果父类也遵守了NSCoding协议,请注意:
  • 应该在encodeWithCoder:方法中加上一句

[super encodeWithCode:encode];

确保继承的实例变量也能被编码,即也能被归档

  • 应该在initWithCoder:方法中加上一句

self = [super initWithCoder:decoder];

确保继承的实例变量也能被解码,即也能被恢复




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

white camel

感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值