1.NSData
NSData是Objective-C語言中數據的基本類型,其成分可以理解為字節指針和長度的封裝的類,來看看源代碼
@interface NSData : NSObject <NSCopying, NSMutableCopying, NSSecureCoding> @property (readonly) NSUInteger length; /* The -bytes method returns a pointer to a contiguous region of memory managed by the receiver. If the regions of memory represented by the receiver are already contiguous, it does so in O(1) time, otherwise it may take longer Using -enumerateByteRangesUsingBlock: will be efficient for both contiguous and discontiguous data. */ @property (readonly) const void *bytes NS_RETURNS_INNER_POINTER; @end
所謂數據之基本單位,就好比是萬物皆為能量,人死后可以轉換成能量(序列化),能量也能孕育成人、或轉換成其他物質(反序列化)。
對象轉NSData這個過程也可以稱為序列化,而NSData轉對象則為反序列化。
在網絡傳輸、數據存儲等地方,NSData是非常常用的。
或者說,任何一門語言里,序列化的數據(類似NSData的數據)都是非常重要的。
2.NSCoding協議
任何對象轉NSData,都需要遵循一個協議,就是NSCoding。
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder; // NS_DESIGNATED_INITIALIZER @end
對於系統的Class,都是默認支持NSCoding協議的,但是如果你自定義了一個對象,比如手動去支持它,如下:
實現NSCoding協議:
(1)在.h文件里
#import <Foundation/Foundation.h> @interface ContactInfo : NSObject<NSCoding> @property int userid; @property (copy) NSString *username; @property (copy) NSString *FriendlyName; @property (copy) NSString *phoneNum; @end
(2)在.m文件里的implementation添加實現NSCoding協議的方法:
//每個屬性變量分別轉碼
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.FYusername forKey:@"username"];
[aCoder encodeObject:self.FriendlyName forKey:@"FriendlyName"];
[aCoder encodeObject:self.phoneNum forKey:@"phoneNum"];
}
//分別把每個屬性變量根據關鍵字進行逆轉碼,最后返回一個Student類的對象
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
self.FYusername = [aDecoder decodeObjectForKey:@"username"];
self.FriendlyName= [aDecoder decodeObjectForKey:@"FriendlyName"];
self.phoneNum= [aDecoder decodeObjectForKey:@"phoneNum"];
}
return self;
}
這樣就建立了任何對象和NSdata之間的橋梁。
在實現NSCoding協議后,可以通過歸檔函數來轉成NSData:
NSData *contactsData=[NSKeyedArchiver archivedDataWithRootObject:ContactsArray];
其中的NSCoder是一個編碼的工具性類,封裝了對象序列化和反序列化的函數,所以實際上,我們並沒有自己寫序列化算法,只是遵循了這個協議讓系統去調用罷了。
3.利用NSData進行存儲和深拷貝
實現NSCoding的類,並序列化數據,有2個好處:
1.序列化數據可以直接進行存儲
2.序列化數據容易進行完全拷貝
1.序列化數據可以直接進行存儲
在iOS中,進行存儲比較快捷的方式是NSUserDefaults,存儲方式如下:
[[NSUserDefaults standardUserDefaults] setObject:nickName forKey:UserDefault_NickName];
[[NSUserDefaults standardUserDefaults] synchronize];
但它支持的數據類型很有限:
NSNumber(NSInteger、float、double),NSString,NSData,NSArray,NSDictionary,BOOL.
一般都是些不可變的基本類型,存儲其他類型時,如NSMutableArray等類型時,會崩潰的。
那腫么辦?
對的,先轉NSData.
NSData *contactsData=[NSKeyedArchiver archivedDataWithRootObject:ContactsArray];
[[NSUserDefaults standardUserDefaults] setObject:contactsData forKey:UserDefault_ContactsArray];
[[NSUserDefaults standardUserDefaults] synchronize];
當然,不能忽略的是,如果是自定義對象,別忘了給他造NSCoding的橋梁。
除了NSUserDefaults,另外存儲NSData的方式可以用歸檔+地址:
[NSKeyedArchiver archiveRootObject:obj toFile:path];
具體如何實現NSCoding協議,使用NSUserdefaults和NSKeyedArchiver進行存儲,參考:
http://www.cnblogs.com/rayshen/p/4910749.html
2.序列化數據容易進行完全拷貝:
難道拷貝對象這么麻煩嗎?對的,要完全拷貝一個對象還真不是那么簡單。
關於對象的拷貝,將在下一篇博客中闡述,這里簡單說下使用NSKeyedArchiver來實現深拷貝:
主要的方法是先將某個對象轉NSData,然后NSData轉回賦值給新建對象:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:oldContactsArray]; NSMutableArray *newContactsArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
