學習到目前為止,我看到oc實現的序列化方式有兩種:NSKeyedArchiver,NSPropertyListSerialization。
在這兩種序列化方式中,NSData都是序列化的目標。兩種方式的不同點在於NSPropertyListSerialization只是針對字典類型的,而NSKeyedArchiver是針對對象的。(補充一下,在Mac OS環境下,還可以使用NSArchiver獲得更加精簡的二進位序列化內容,但是NSArchiver在iOS環境下不支援)。
首先講NSPropertyListSerialization,這個相對簡單,只要建立一個NSDictionary,然後調用NSPropertyListSerialization dataFromPropertyList, 將內容寫入NSData中就可以了。如果要讀入,就調用propertyListFromData.
NSString * filepath = @”…”;//omitted.NSString * err;//不需要初始化。如果有錯誤發生,會被複製。NSDictionary * props = [NSDictionary dictionaryWithObjectsAndKey:@”Lucy”, @"name”, @"Beijing, China”, @"city”, @"supervior”, @"position”, @"Qitiandasheng”, @"company”, nil];NSData * data = [NSPropertyListSerialization dataFromPropertyList:propsformat:NSPropertyListXMLFormat_v1_0 errorDescription:&err];if(!err){[data writeToFile:filePath atomically:YES];//寫入檔案}else{NSLog(@"error with:%@", err);}
然後再來看NSKeyedArchiver。從基本的程式碼範例來看也很簡單:
Person * lucy = [[Person alloc] initWithName:@"lucy"];lucy.address = @"Beijing, China";NSData * data = [NSKeyedArchiver archiveDataWithRootObject:lucy];[data writeToFile:filePath];
這裡要求Person類必須事先了NSCoding協議。NSCoding協議中包含兩個必須事先的方法initWithCoder和encodeWithCoder. 參考下面這兩個方法的實現:
-(void)encodeWithCoder:(NSCoder *)aCoder{[aCoder encodingObject:[NSNumber numberWithInt:self.age] forKey @"age"];}-(id)initWithCoder:(NSCoder*) aDecoder{if(self=[super init]){self.age = (int)[(NSNumber*)[aDecoder decodeObjectForKey:@"age"] intValue];}return self;}
這裡之所以用int age作為序列化屬性的樣本,是為了引出另一個話題,就是在序列化時對基礎類型的處理。NSCoder中是不能儲存基礎類型的,包括int,float,char *什麼的。要將這些進行序列化,必須要進行封裝。
一般封裝有兩種方式。對於數值基本類型,使用Cocoa提供的封裝,NSNumber就可以了。對於定長的struct,要分情況,如果struct的所有類型都是定長,並且成員中沒有struct類型,那麼可以直接使用NSValue來封裝;否則,需要自己想辦法進行key-value編寫。char * 應該直接使用NSString進行封裝。