你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> 歸檔自定義對象

歸檔自定義對象

編輯:關於IOS

Cocoa中,歸檔數據到文件,使用NSKeyedArchiver的archiveRootObject:toFile:方法。對於一般的數據類型(例如字符串),這個步驟是非常簡單的。Apple官方文檔中,這些數據類型包括:

    NSData     NSString     NSNumber     NSDate     NSArray     NSDictionary 很顯然,復雜數據例如UIImage,無法直接歸檔。但我們有一種變通的做法,先將UIImage對象轉換為NSData,再對NSData進行歸檔。 注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
 
@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 &amp;&amp; tfName.text.length&gt;0 &amp;&amp; tfAge&amp;&amp; tfAge.text.length&gt;0) {
 
           button.tag=1;
 
           ;
 
           MyClass* obj=[self makeMyClassInstance];
 
           [NSKeyedArchiver archiveRootObject:obj toFile:filePath];
 
           [self initUI:nil];
 
       }
 
       
 
    }else{
 
       button.tag=0;
 
       ;
 
       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; 程序運行結果如下所示: 歸檔自定義對象
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved