iOS数据持久化属性列表及对象归档的封装
在iOS上的数据持久化的解决方案总的来说有四种。分别是NSUserDefaults
属性列表、NSKeyedArchiver
对象归档、SQLite3数据库以及苹果官方提供的基于SQLite3进行二次封装的Core Data。
对于以上四种方案的优劣以及用途比较,之前已经看过很多文章有所讲解,其中有一篇文章对于这四种方案的使用讲解的非常透彻清晰,如果有需要的朋友可以移步iOS中几种数据持久化方案:我要永远地记住你!
今天我们来讨论一下关于NSUserDefaults
属性列表与NSKeyedArchiver
对象归档两种方式的使用以及封装。
使用及注意
NSUserDefaults
属性列表和NSKeyedArchiver
对象归档是iOS中两种非常常用的数据持久化方案。这两者均由系统提供,所以用起来非常简单方便。下面分别就两者的使用和注意事项作简单介绍。
NSUserDefaults
NSUserDefaults
是一个极好的方式,用于存储轻量级数据,比如用户习惯、用户清单等等。这个类存在一个单例模式的实例对象standardUserDefaults,我们可以利用这个实例对象来保存程序启动默认设置等。
NSUserDefaults所支持的数据类型较为传统、典型,包括NSString
、NSDate
、NSURL
、NSArray
、NSDictionary
、BOOL
以及NSInteger
、float
和double
。
在通常情况下,我们使用+ (NSUserDefaults *)standardUserDefaults;
来获取一个单例模式的NSUserDefaults。当然苹果也提供了另外一个方法- (nullable instancetype)initWithSuiteName:(nullable NSString *)suitename;
,使我们能够开辟一个不同于standardUserDefaults的实例。这个方法在iOS 7之前的前身是- (nullable id)initWithUser:(NSString *)username;
。
由此可见,我们每次使用单例模式的userDefaults,都可以比较简单的完成。
特别注意:
NSUserDefaults
无法处理可变类型数据,如NSMutableString
、NSMutableArray
等,想要存储可变对象,可利用不可变数据类型实例对象做桥接。- 归档数据所需的key必须是唯一的,多次对同一个key设置对象会导致之前设置的对象被覆盖掉。
存取自定义类型
对于非前文所述数据类型,我们同样可以利用NSUserDefaults
处理它们,这得益于NSUserDefaults
提供了针对任意对象处理的方法:
|
|
假设我们定义如下的数据模型:
|
|
显然想要吧snoopy
归档,我们肯定不能直接在setObject: forKey:
方法中直接对snoopy
对象进行操作,直接操作的后果就是crash。但我们可以利用NSKeyedArchiver
对NSData
对象进行桥接。
Dog
类实例对象转化为NSData
,然后将其归档至NSUserDefaults
:
|
|
读取对象的时候,过程是是一样的,也是先取出NSData
类对象,然后再转化为Dog
类。
|
|
NSKeyedArchiver
刚刚前文介绍的,通过把自定义数据类模型转化为NSData
再归档至NSUserDefaults
的方法,其实已经用到了NSKeyedArchiver
的编解码方法。我们能对NSData
对象这样归档的原因正是NSData
类已经实现了NSCoding
协议。所有实现了NSCoding
协议的类,都可以直接通过NSKeyedArchiver
进行归档。
而具体的实现方式,其实是和NSUserDefaults
没有太大区别的,在此不表。
封装
任意类归档原理
刚刚提到了,对于任意实现了NSCoding
协议的类,都可以直接归档。那么这个协议如何实现?
|
|
显然,一个作为编码一个作为解码。
|
|
实现以上编解码方法,并将其作为NSObject
的扩展,即可完成对任意对象归档的准备工作(NSObject
作为一切类的根类)。
封装实现
沙盒
沙盒是iOS中用于存储应用数据的位置,每个应用都存在独立的沙盒,所以不会互相影响,更不会影响系统文件。
获取沙盒路径:
|
|
文件操作
归档文件、读取文件、删除单个文件:
|
|
path是沙盒路径后接文件名的字符串,比如我这里的demo是”/var/mobile/Containers/Data/Application/4CBD28A1-126C-4BC0-A5CD-FAC43B413271/Documents/fileName.plist“
开个脑洞,若想设备沙盒中所有文件怎么办?
同样的,获取沙盒路径,之后通过方法- (nullable NSArray<NSString *> *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error
获得来自该路径下的所有文件数组,再对其进行遍历,对文件进行筛选,对需要删除的文件调用remove方法即可。完整的方法如下:
|
|