前言:做了一个图片浏览的小demo,支持随意添加、删除图片,图片放大、缩小,带矩形框的截图。随后几篇博客都会详细讲解在此过程中遇到的各种问题。这篇主要讲,在做添加、删除这个功能时,遇到的存文件的问题。
我们想实现在以后每次打开这个程序时,不用再一张张手动添加,而会保留用户上次已经选择的图片,那么就需要把这些图片存入内存,每次从内存中读取。
正文:
一、存文件有几种方式?
直接写入FILE、对象序列化
二、直接写入FILE
在我的程序里,我是把图片都存在一个NSMutableDictionary,每个image都对应一个key。
1、直接调用NSDictionary的writeToFile:atomically:方法,将dic存入一个指定的目录。
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flagDescription
功能:Writes a property list representation of the contents of the dictionary to a given path.
把一个代表这个dictionary内容的property列表写入到指定的路径。
出现问题:目录创建没有问题,但是一直writeToFile写入失败??
分析思路: 查询方法注释,有这样一段话:
这个方法在把dic写入文件之前,会递归的验证所有包含的对象是否都是property列表里的对象(包括 NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary)。
如果dic中所有的对象不全是property列表里的对象,那么返回NO,因为最后生成的文件不是一个有效的 property list.
失败原因:是因为我的dic中存的obj是UIImage,不属于property list,所以返回失败。
解决办法:把UIImage换成property list里的对象NSData,把NSData存入dic中。
NSData *data = UIImagePNGRepresentation(img);
2、从FILE中取出
在writeToFile的注释中,写到:If the dictionary’s contents are all property list objects, the file written by this method can be used to initialize a new dictionary with the class method dictionaryWithContentsOfFile: or the instance method initWithContentsOfFile:.
如果这个dic的内容都是property list,那么通过这个方法写的文件可以用来初始化一个新的dictionary,方法:dictionaryWithContentsOfFile:或者initWithContentsOfFile:.
NSMutableDictionary *dic= [NSMutableDictionary dictionaryWithContentsOfFile:_filePath];
问题:在写入成功后,我调用这个dictionaryWithContentsOfFile时,得到的新dic总是有问题。
分析原因:写入问题?参数_filePath问题?写入如果有问题的话,那么根本就不会成功,换了一个新的path成功了,说明是_filePath的问题。在失败的打印框中输入po _filePath,果然是个空指针。这个问题是我怎么都没有想到的。我把_filePath定为全局变量,在一开始的init方法中,就给它赋了值,可是这里它怎么会是nil了??
来看一下我的赋值方法:
_filePath = [NSString stringWithFormat:@"%@/Documents/imageViews/test.plist",NSHomeDirectory()];
现在知道问题出在哪了吧?!!在前面的博客中详细分析过这个问题,凡是没有用alloc等方法构造的对象,如果在程序的其他地方还要用的话,一定要加上retain!!!
修改后一切ok!
三、对象序列化
在接触新内容时,我们先来回顾一下java的对象序列化。在java中,需要序列化的对象必须实现Serializable接口,通过调用writeObject、readObject这两个方法存储、读取对象。
在oc中,也是类似的。需要序列化的对象必须实现NSCoding协议并重写encodeWithCoder和initWithCoder两个方法,分别用以编码和反编码,通过调用NSKeyedArchiver、NSKeyedUnarchiver这两个类来存储、读取对象。如果继承的类已经实现了NSCoding协议,那么子类就不用实现了。
[NSKeyedArchiver archiveRootObject:obj toFile:filename]; //序列化 obj = [NSKeyedUnarchiver unarchiveObjectWithFile: filename]; //反序列化
因为目前还没有尝试,就简单介绍一下,用到的时候再详细研究。可参考:http://blog.csdn.net/holydancer/article/details/7371643
四、总结
1、writeToFile方法,只适用于 NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary这些类。
2、我们自定义的类要写入文件,都是用序列化方法。