標籤:
軟體中永遠繞不開的一個問題就是資料存放區的問題,PC的時候一般都是選擇在資料庫中儲存,iOS如果是和後端配合的話,那麼不需要考慮資料存放區的這個問題,上次寫了一下plist的儲存,不過資料都是儲存一些簡單的索引值對對象。本次需要將一些自己定義的類型儲存在plist比如說圖片,這個時候可以利用NSCoding協議,將資料地以類似檔案的形式儲存到plist檔案中,然後從plist的檔案中讀取資料,使用協議的時候這個時候就會用到了NSCoder,如果對存檔和解壓沒有概念的話,可以簡單的理解為資料的序列化與還原序列化。
基礎概念
NSCoding是一個protocol. 如果實現了NSCoding,需要實現其中的兩個方法:
- (void)encodeWithCoder:(NSCoder *)aCoder;- (id)initWithCoder:(NSCoder *)aDecoder; // NS_DESIGNATED_INITIALIZER
方法中的主要的參數就是NSCoder,它是archivie位元組流的抽象類別.可以將資料寫入一個coder,也可以從coder中讀取我們寫入的資料. NSCoder是一個抽象類別,不能直接使用它來建立對象. 但是可以通過其子類NSKeyedUnarchiver從位元組流中讀取資料,NSKeyedArchiver將對象寫入到位元組流。本文以書籍為例:
建立一個Book類,Book.h中的代碼:
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface Book : NSObject<NSCoding>@property (strong,nonatomic) UIImage *ConverPicture;@property (strong,nonatomic) NSString *BookName;@property (strong,nonatomic) NSString *Author;@property (strong,nonatomic) NSNumber *Price;@end
Book.m中實現NSCoding的兩個方法,注意中UIImage的寫法與其他有所不同:
@implementation Book- (void)encodeWithCoder:(NSCoder *)aCoder{ //注意這裡是儲存的是JPG圖片的調用 [aCoder encodeObject:UIImageJPEGRepresentation(self.ConverPicture,1.0)forKey:@"ConverPicture"]; [aCoder encodeObject:_BookName forKey:@"BookName"]; [aCoder encodeObject:_Author forKey:@"Author"]; [aCoder encodeObject:_Price forKey:@"Price"]; }- (id)initWithCoder:(NSCoder *)aDecoder{ self.ConverPicture=[UIImage imageWithData:[aDecoder decodeObjectForKey:@"ConverPicture"]]; self.BookName=[aDecoder decodeObjectForKey:@"BookName"]; self.Author=[aDecoder decodeObjectForKey:@"Author"]; self.Price=[aDecoder decodeObjectForKey:@"Price"]; return self; }@endDemo實現
正常的情況的不需要建立頁面的,不過需要示範一下UIImage的效果,Main.storyboard中的布局:
稍微解釋一下,前兩個是存的單檔案,後兩個存的是多檔案,UIImage展示儲存的圖片:
ViewController定義欄位:
@property (strong,nonatomic) NSString *storagePath;@property (strong,nonatomic) NSString *storageListPath;@property (strong,nonatomic) NSMutableArray *bookList;
設定路徑,如果不是很清晰,可參考本文之前的部落格:
NSArray *codepath= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); _storagePath = [codepath[0] stringByAppendingPathComponent:@"book.plist"]; NSLog(@"%@",NSHomeDirectory()); _storageListPath = [codepath[0] stringByAppendingPathComponent:@"booklist.plist"];
單個存檔:
Book *book=[[Book alloc]init]; UIImage *image=[UIImage imageNamed:@"Code1.jpg"]; book.ConverPicture=image; [email protected]"百年孤獨"; [email protected]"加西亞.馬爾克斯"; book.Price=[[NSNumber alloc] initWithInteger:45]; if ([NSKeyedArchiver archiveRootObject:book toFile:_storagePath]) { NSLog(@"資料存檔成功"); }
單個解壓:
Book *decodeBook=[NSKeyedUnarchiver unarchiveObjectWithFile:_storagePath]; self.myImageView.image=decodeBook.ConverPicture; NSLog(@"%@",decodeBook.ConverPicture); NSLog(@"%@",decodeBook.BookName); NSLog(@"解檔成功");
多個存檔:
self.bookList=[NSMutableArray array]; for (NSInteger i=1; i<3; i++) { Book *book=[[Book alloc]init]; NSString *imageName=[NSString stringWithFormat:@"Code%ld.jpg",(long)i]; UIImage *image=[UIImage imageNamed:imageName]; book.ConverPicture=image; book.BookName=[NSString stringWithFormat:@"百年孤獨%ld",(long)i]; book.Author=[NSString stringWithFormat:@"加西亞.馬爾克斯%ld",(long)i]; book.Price=[[NSNumber alloc] initWithInteger:45]; [self.bookList addObject:book]; } if ([NSKeyedArchiver archiveRootObject:self.bookList toFile:_storageListPath]) { NSLog(@"資料存檔成功"); }
多個解檔:
self.bookList=[NSKeyedUnarchiver unarchiveObjectWithFile:_storageListPath]; Book *nextBook=self.bookList[1]; self.myImageView.image=nextBook.ConverPicture; NSLog(@"解檔成功");
通過代碼基本上發現其實存檔和解壓是非常簡單的一個事情,不過事實這種方式缺點還是很明顯的,以這種方式儲存資料只能一次性歸檔儲存以及一次性解壓。資料較少的時候如果使用感覺比較方便,資料量過多的時候如果想修改其中的某一條,解壓整個資料然後歸檔整個資料還是比較耗時的。最終示範效果如下:
參考資料:https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Articles/creating.html#//apple_ref/doc/uid/20000949-BABGBHCA
iOS開發-資料存放區NSCoder