(转载)NSUserDefaults 保存数据
2016-06-12 19:25
399 查看
【问题】
在折腾:
给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 的
NSKeyedUnarchiver
Class Reference 的
对应的,自定义对象本身,需要遵循NSCoding,其有两个函数:
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偶尔/有时候保存数据会失败/失效
在折腾:
给Your
Second iOS App:BirdWatching添加支持程序退出后,用户数据仍然保留
的过程中,遇到一个问题,需要将一个自定义对象的数组,保存到NSUserDefaults。
【解决过程】
1.经过学习很多资料后,然后加上一番折腾,先去实现了单个自定义对象的编解码和存储/恢复:
贴出部分相关的代码:
BirdSighting.h:
?
?
?
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. 包含了几个自己的不同类型的属性
?
A。实现了对应的NSCoding的encodeWithCoder,将对应的不同的属性变量编码为对应数据
B。实现了对应的NSCoding的initWithCoder,从对应的 key中解码出数据还原到对应的属性变量中
?
先说背景条件:
BirdSightingDataController是个Controller
在对应的头文件BirdSightingDataController.h中,定义了个属性变量,是 自定义对象BirdSighting的数组 NSMutableArray
?
以及对应的也可以从NSUserDefaults中还原出masterBirdSightingList。
(1)编码 masterBirdSightingList(自定义对象BirdSighting的数组NSMutableArray) 到 NSUserDefaults 中
?
?
如此,就可以实现,将 自定义对象的数组 保存到 NSUserDefaults 了。
特别提示:
如果你遇到数据偶尔没有保存成功的话,那和你要保存的变量,以及NSCoder对象是否是autoRelease的,没有半毛钱关系,而是和iOS中数据同步写回有关系。
解决办法参见:
【已解决】NSUserDefaults偶尔/有时候保存数据会失败/失效
相关文章推荐
- 【一天一道LeetCode】#90. Subsets II
- 【一天一道LeetCode】#90. Subsets II
- UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(一)
- 《2016互联网趋势报告》解读(一)
- mysql排序order by新发现
- 数学(错排):BZOJ 4517: [Sdoi2016]排列计数
- Javaworkers团队第五周项目总结
- 月月月月月月月月
- [javaEE] response实现图片下载
- windows程序设计(2)---窗口的创建
- Qt浅谈之二十七进程间通信之QtDBus
- Two Sum
- Activity生命周期、启动方式及常见Activity
- Android入门--style.xml设置和应用
- linux给用户添加sudo权限
- DIV与CSS的结合使用
- <Js>运算
- java用正则方法验证文件名是否合法
- ADO.NET基础巩固-----连接类和非连接类
- PowerDesigner 把Comment写到name中 和把name写到Comment中 pd7以后版本可用