歸檔自訂對象

來源:互聯網
上載者:User

Cocoa中,歸檔資料到檔案,使用NSKeyedArchiver的archiveRootObject:toFile:方法。對於一般的資料類型(例如字串),這個步驟是非常簡單的。Apple官方文檔中,這些資料類型包括:     NSData     NSString     NSNumber     NSDate     NSArray     NSDictionary 很顯然,複雜資料例如UIImage,無法直接歸檔。但我們有一種變通的做法,先將UIImage對象轉換為NSData,再對NSData進行歸檔。www.2cto.com 注1:準確地說,這依賴於iOS的版本。在iOS4中,UIImage未實現NSCoding協議,在iOS5中,UIImage實現了NSCoding協議。 對於自訂的類型,我們也可以參考這一做法,即先將將自訂類型轉換為NSData,再對NSData進行歸檔。 問題在於,NSKeyedArchiver在歸檔一個自訂對象時,怎麼知道如何將一個自訂對象編碼為一個NSData?而且,當我們從檔案中反歸檔時,NSKeyedUnarchiver怎麼知道將NSData轉變為一個自訂對象? 這就是NSCoding 協議需要解決的問題。實際上,NSCoding協議規定的兩個方法,分別用於解決這兩個問題。 當NSKeyedArchiver 在歸檔一個對象時,將調用對象的encodeWithCoder:方法,用於將對象轉換為NSData(或NSString等其他5種類型);而NSKeyedUnarchiver在反歸檔一個對象時,則調用對象的initWithCoder:方法,用於將NSData(或NSString等其他5種類型)轉換為指定的物件類型。 上述6種類型(NSData、NSString等)在歸檔/反歸檔時顯得尤其簡單,是因為蘋果已經為我們實現了NSCoding協議。 而自訂對象不同,需要程式員自己實現其NSCoding協議。 建立項目,建立一個類MyClass,在標頭檔中聲明對NSCoding協議的實現。 然後為他設計屬性如下: @interface MyClass : NSObject<NSCoding> @property(strong,nonatomic)NSString* name; @property(assign,nonatomic)int age; @property(assign,nonatomic)BOOL sex; @end 然後,在實現中實現NSCoding協議: @implementation MyClass @synthesize name,age,sex; -(void)encodeWithCoder:(NSCoder *)encoder{     [encoderencodeObject:self.name forKey:@"name"];     [encoderencodeObject:[NSNumber numberWithInt: self.age] forKey:@"age"];     [encoderencodeObject:[NSNumber numberWithBool: self.sex] forKey:@"sex"]; } - (id)initWithCoder:(NSCoder *)decoder {     if (self = [superinit]) {        self.name = [decoder decodeObjectForKey:@"name"];        self.age =((NSNumber*)[decoderdecodeObjectForKey:@"age"]).intValue;        self.sex =((NSNumber*) [decoderdecodeObjectForKey:@"sex"]).boolValue;     }     return self;    } @end 在encodeWithCoder:方法中,這兩句好像顯得有點多餘: [encoder encodeObject:[NSNumber numberWithInt: self.age]forKey:@"age"]; [encoder encodeObject:[NSNumber numberWithBool: self.sex]forKey:@"sex"]; 然而事實並不是這樣的,encoder對象只能對已經實現了NSCoding的對象進行編碼(即轉換為6種類型之一),對於int、BOOL這樣的簡單類型則不行。因此,我們需要對age和sex屬性轉換為其他類型(6種類型之一),比如NSNumber。 同樣,在initWithCoder:方法中,我們必須對decoder反編碼後的資料進行必要的轉換,將它們由NSNumber(因為編碼時我們是用NSNumber儲存的)轉換為相應屬性原來的類型,才能進行賦值: self.age =((NSNumber*)[decoderdecodeObjectForKey:@"age"]).intValue; self.sex =((NSNumber*) [decoder decodeObjectForKey:@"sex"]).boolValue; 接下來,我們使用NSKeyedArchiver/NSKeyedUnarchiver來對MyClass進行歸檔/反歸檔。 開啟ViewController.xib,設計如下UI介面:    使用Asistant Editor,建立必要的串連。這時ViewController.h檔案內容將顯示如下: #import "MyClass.h" #define AppDocuments [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0] @interface ViewController : UIViewController<UITextFieldDelegate> @property (retain, nonatomic) IBOutlet UITextField *tfName; @property (retain, nonatomic) IBOutlet UITextField *tfAge; @property (retain, nonatomic) IBOutlet UISegmentedControl *segSex; @property (retain, nonatomic) IBOutlet UIButton *button; - (IBAction)archiveUnarchive:(id)sender; @end 在ViewDidLoad方法中,加入語句 [self initUI:nil]; 其中,initUI:方法定義如下: -(void)initUI:(MyClass*)obj{     if (obj==nil) {        tfName.text=nil;        tfAge.text=nil;        segSex.selectedSegmentIndex=0; }else{        tfName.text=obj.name;        tfAge.text=[NSString stringWithFormat:@"%d",obj.age];        segSex.selectedSegmentIndex=obj.sex; } } 定義方法makeMyClassInstance,在這個方法中我們通過使用者在介面是輸入的內容建立MyClass執行個體: -(MyClass*)makeMyClassInstance{     MyClass*obj=[[MyClass alloc]init];    obj.name=tfName.text;     obj.age=[tfAge.textintValue];     obj.sex=[segSexselectedSegmentIndex]!=0;     return [objautorelease]; } 定義按鈕事件的Action方法如下: - (IBAction)archiveUnarchive:(id)sender {    button.enabled=NO;     NSString*filePath=[AppDocuments stringByAppendingPathComponent:@"customobject.txt"];     if(button.tag==0) {        if (tfName && tfName.text.length>0 && tfAge&& tfAge.text.length>0) {            button.tag=1;            [button setTitle:@"反歸檔" forState:UIControlStateNormal];            MyClass* obj=[self makeMyClassInstance];            [NSKeyedArchiver archiveRootObject:obj toFile:filePath];            [self initUI:nil];        }             }else{        button.tag=0;        [button setTitle:@"歸檔" forState:UIControlStateNormal];        MyClass* obj=[NSKeyedUnarchiver unarchiveObjectWithFile:filePath];        [self initUI:obj];     }    button.enabled=YES; } 運行程式,在介面中輸入一些資訊,然後點擊“歸檔”按鈕。歸檔後,使用者輸入將再次清空,“歸檔”按鈕將顯示為“反歸檔”。在應用程式的documents目錄,我們將找到歸檔檔案customeobject.txt。  回到程式,點擊“反歸檔”按鈕,將再次從customobject.txt檔案中擷取MyClass對象,並將對象屬性讀取到UI控制項中。 除了直接將MyClass對象作為RootObject(根對象)歸檔到檔案以外,更通常的做法是將MyClass對象放入集合(Array或Dictionary),再對集合對象進行歸檔。 此外,MyClass可以遞迴,即它的屬性可以是另一個MyClass對象並且這個屬性也可以被歸檔和反歸檔。 我們可以在MyClass中增加屬性parent,然後在encodeWithCoder:方法中增加此句: if(self.parent)[encoder encodeObject:self.parent forKey:@"parent"]; 同樣在initWithCoder:方法中加入: self.parent=[decoder decodeObjectForKey:@"parent"]; 這樣,在makeMyClassInstance方法中,我們可以為obj物件建構另一個MyClass對象作為他的parent屬性: MyClass* parent=[[MyClass alloc]init]; parent.name=@"dad"; parent.age=obj.age+20; parent.sex=0; parent.parent=nil; obj.parent=parent; 在反歸檔之後,我們可以在initUI方法中顯示parent的資訊: lbParent.text=obj.parent.name; 程式運行結果如下所示:  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.