您的位置:首页 > 移动开发 > Objective-C

【已解决】iPhone/iOS中保存自定义对象(Custom Object/Custom Class)的数组(NSMutableArray/NSArray)到NSUserDefaults

2016-01-04 23:48 721 查看


【已解决】iPhone/iOS中保存自定义对象(Custom Object/Custom Class)的数组(NSMutableArray/NSArray)到NSUserDefaults

2012
年 11 月 26 日 上午 12:57crifan已有17063人围观7个评论

【问题】

在折腾:

给Your
Second iOS App:BirdWatching添加支持程序退出后,用户数据仍然保留

的过程中,遇到一个问题,需要将一个自定义对象的数组,保存到NSUserDefaults。

【解决过程】

1.经过学习很多资料后,然后加上一番折腾,先去实现了单个自定义对象的编解码和存储/恢复:

贴出部分相关的代码:

BirdSighting.h:

?
BirdSighting.m:

?
BirdSightingDataController.m:

?
如此,暂时可以实现了,单个的对象,每次保存后,下次恢复,也可以完整的恢复出来数据并正确显示:





2.后来也参考了很多帖子:

How
to store custom objects in NSUserDefaults

save
and restore an array of custom objects

How
to archive an NSArray of custom objects to file in Objective-C

3.但是我这里又遇到一个问题,那就是,我此处需要保存的是自定义对象的数组,即用一个数组指针指向的多个自定义对象,所以,就没法直接使用上述方法保存这一系列自定义对象了,所以还要想其他办法才行。

但是后来却发现,其实上述原先的代码,本身已经可以工作了。

即,解码的时候,可以看到能从NSUserDefaults获得一堆的数据了:





对应的,在恢复自定义对象数组masterBirdSightingList之前,其是null:





然后调用unarchiveObjectWithData时,也可以执行对应的自定义对象的initWithCoder函数了:





解码后,对应的masterBirdSightingList就包含了还原出来的2个对象了:





而编码过程也是所期望的:

先是NSData是空的:





然后调用archivedDataWithRootObject去编码,可以调用到自定义对象的encodeWithCoder函数:





然后经过4个对象的编码后,就包含了编码后的数据了:





接着就是正常的保存到NSUserDefaults中去了.

如此,关闭程序之前的显示的数据是:





恢复后的显示的效果为:





很明显,两者完全一样,即整套逻辑是正常工作的,可以完美的实现自定义对象的数组的保存和恢复.

下面对整个逻辑和示例代码,进行详细的总结。

【总结】

【自定义对象的数组NSMutableArray,保存到/恢复自
NSUserDefaults 的逻辑】

想要实现自定义类型的对象的数组,保存到NSUserDefaults中去,核心的逻辑是:

1.想要把数据保存到NSUserDefaults中的话,那首先要知道NSUserDefaults所支持的数据类型。

根据官网

NSUserDefaults
Class Reference

的解释,默认支持类型是:

NSData

NSString

NSNumber

NSDate

NSArray

NSDictionary

所以,如果你本身要保存的数据是属于上述中已有的,常见的,数据类型,比如NSString,NSDate之类的话,那么很简单,直接保存即可。

2.而此处所谓的自定义对象(Custom Object)/类(Class)的话,常见的做法是,把自定义对象转换为NSData,然后利用NSUserDefaults去保存NSData。

把自定义对象转换为NSData,用的方法就是Archive,Archive可翻译为归档,压缩。

相关的方法是:

NSKeyedArchiver
Class Reference 的
+
archivedDataWithRootObject:


NSKeyedUnarchiver
Class Reference 的
+
unarchiveObjectWithData:


对应的,自定义对象本身,需要遵循NSCoding,其有两个函数:

–
initWithCoder:
:解码

–
encodeWithCoder:
: 编码

3. 之后:

当你的使用NSKeyedArchiver去把自定义对象编码为NSData时,就会调用到该对象的encodeWithCoder,编码后得到了NSData后,再保存到NSUserDefaults里面;

当你从NSUserDefaults读取出你之前所保存的NSData之后,再调用NSKeyedUnarchiver去解码此NSData,然后内部会自动调用到该自定义对象的initWithCoder方法,将NSData解码为对应的自己的对象

如此,就可以实现将自定义对象保存到NSUserDefaults和从NSUserDefaults恢复之前保存的自定义对象了。

4.上述方法,看似是只针对单个自定义对象的,但是本质上,对于自定义对象的数组,也是适用的。

因为,对于一般的NSMutableArray来说,其本身也是实现了NSCoding,所以,当你去使用NSKeyedArchiver将一个自定义对象的NSMutableArray数组编码为NSData时,其内部会先调用NSMutableArray的encodeWithCoder,然后发现是个自定义对象的数组,然后就会分别针对每个自定义对象调用该自定义对象的encodeWithCoder,这样,最终实现了将整个自定义对象数组,转换为NSData;

相应的解码过程也是一样的,当从NSData解码为对应的自定义对象的NSMutableArray数组时,也是先调用NSMutableArray的initWithCoder,然后分别调用每个自定义对象的initWithCoder,最终解码为对应的自定义对象的NSMutableArray数组。

【自定义对象的数组NSMutableArray,保存到/恢复自
NSUserDefaults 的 参考代码】

1. 自定义对象BirdSighting

(1)对应的头文件中:

A. 实现了遵循NSCoding(Conform to NSCoding)

B. 包含了几个自己的不同类型的属性

?
(2)对应BirdSighting.m中

A。实现了对应的NSCoding的encodeWithCoder,将对应的不同的属性变量编码为对应数据

B。实现了对应的NSCoding的initWithCoder,从对应的 key中解码出数据还原到对应的属性变量中

?
2. 在别处将自定义对象BirdSighting的数组保存到和读取自NSUserDefaults

先说背景条件:

BirdSightingDataController是个Controller

在对应的头文件BirdSightingDataController.h中,定义了个属性变量,是 自定义对象BirdSighting的数组 NSMutableArray

?
然后想要在Controller的实现文件BirdSightingDataController.m中,保存这个 自定义对象BirdSighting的数组NSMutableArray, 即属性变量masterBirdSightingList 到 NSUserDefaults,

以及对应的也可以从NSUserDefaults中还原出masterBirdSightingList。

(1)编码 masterBirdSightingList(自定义对象BirdSighting的数组NSMutableArray) 到 NSUserDefaults 中

?
(2) 从 NSUserDefaults 中 解码还原出 (自定义对象BirdSighting的数组NSMutableArray)masterBirdSightingList

?
其中,两者的key要一致,即此处两处都使用同一个"BirdSightingList"。

如此,就可以实现,将 自定义对象的数组 保存到 NSUserDefaults 了。

特别提示:

如果你遇到数据偶尔没有保存成功的话,那和你要保存的变量,以及NSCoder对象是否是autoRelease的,没有半毛钱关系,而是和iOS中数据同步写回有关系。

解决办法参见:

【已解决】NSUserDefaults偶尔/有时候保存数据会失败/失效
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: