前言:做了一個圖片瀏覽的小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、我們自定義的類要寫入文件,都是用序列化方法。