OC學習篇之---歸檔和解擋 分類: IOS 2014-12-11 21:18 2943人閱讀 評論(0) 收藏

前幾篇文章說到了OC中的Foundation框架:http://blog.csdn.net/jiangwei0910410003/article/details/41852835,今天咱們來看一下OC中的一個重要知識點:歸檔java

OC中的歸檔就是將對象寫入到一個文件中,Java中的ObjectInputStream和ObjectOutputStream來進行操做的。固然在操做的這些對象都是須要實現一個接口:Serializable,一樣的OC中操做的對象也是須要實現一個協議的,後面會說到。app


1、已有類型的歸檔和解檔框架

首先來看一個簡單的例子:iphone

//
//  main.m
//  33_ObjectToFile
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//

#import <Foundation/Foundation.h>

//歸檔:將一個對象寫到文件中
int main(int argc, const char * argv[]) {
    @autoreleasepool {
       //第一種形式:歸檔對象
       //對象----》文件
        /*
        NSArray *array = [NSArray arrayWithObjects:@"zhang",@"wangwu",@"lisi",nil];
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
        
        BOOL success = [NSKeyedArchiver archiveRootObject:array toFile:filePath];
        if(success){
            NSLog(@"保存成功");
        }
         */
        /*解歸檔
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
        id array = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
        NSLog(@"%@",array);
         */
        
        //第二種方式
        //第一種方式的缺陷是一個對象歸檔成一個文件
        //可是第二種方式,多個對象能夠歸檔成一個文件
        /*
        NSArray *array = [NSArray arrayWithObjects:@"zhangsan",@"lisi", nil];
        NSMutableData *data = [NSMutableData data];
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
        //編碼
        [archiver encodeObject:array forKey:@"array"];
        [archiver encodeInt:100 forKey:@"scope"];
        [archiver encodeObject:@"jack" forKey:@"name"];
        
        //完成編碼,將上面的歸檔數據填充到data中,此時data中已經存儲了歸檔對象的數據
        [archiver finishEncoding];
        [archiver release];
        
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
        BOOL success = [data writeToFile:filePath atomically:YES];
        if(success){
            NSLog(@"歸檔成功");
        }
         */
        
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
        //讀取歸檔數據
        NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];
        
        //建立解歸檔對象,對data中的數據進行解歸檔
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        
        //解歸檔
        NSArray *array = [unarchiver decodeObjectForKey:@"array"];
        NSLog(@"%@",array);
        
        int value = [unarchiver decodeObjectForKey:@"scope"];
        NSLog(@"%d",value);
        
        
        

    }
    return 0;
}


一、歸檔

//第一種形式:歸檔對象
//對象----》文件
 NSArray *array = [NSArray arrayWithObjects:@"zhang",@"wangwu",@"lisi",nil];
 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
 
 BOOL success = [NSKeyedArchiver archiveRootObject:array toFile:filePath];
 if(success){
     NSLog(@"保存成功");
 }
咱們這裏將一個NSArray對象寫入到一個文件中。

這裏說到了建立一個文件的方法:編碼

 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];

咱們能夠打印一下filePath的值:atom


NSHomeDirectory()返回的就是當前用戶路徑加密

咱們查看一下array.src的內容:spa


咱們看到內容是亂的,可是咱們貌似仍是能看到一點,好比wangwu/lisi等字眼,說明在歸檔的時候並無深刻的加密。.net


二、解檔

//解歸檔
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
id array = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"%@",array);
解檔也是很簡單的,就是返回一個對象,不過這裏用了id類型的,由於讀出來也不肯定是哪一種類型的。


三、對多個對象進行歸檔到一個文件code

//第二種方式
//第一種方式的缺陷是一個對象歸檔成一個文件
//可是第二種方式,多個對象能夠歸檔成一個文件
 NSArray *array = [NSArray arrayWithObjects:@"zhangsan",@"lisi", nil];
 NSMutableData *data = [NSMutableData data];
 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
 //編碼
 [archiver encodeObject:array forKey:@"array"];
 [archiver encodeInt:100 forKey:@"scope"];
 [archiver encodeObject:@"jack" forKey:@"name"];
 
 //完成編碼,將上面的歸檔數據填充到data中,此時data中已經存儲了歸檔對象的數據
 [archiver finishEncoding];
 [archiver release];
 
 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
 BOOL success = [data writeToFile:filePath atomically:YES];
 if(success){
 NSLog(@"歸檔成功");
 }
多個對象歸檔的話,這裏要用到一個類: NSMutableData和NSData,他們兩的區別很簡單,一個是可變的,一個是不可變的。而後這裏還建立了一個歸檔器:NSKeyedArchiver,這個類負責進行指定類型的編碼操做,而後將數據填充到NSMutableData類。歸檔的時候對每一個類型對象用一個key進行對應,這個NSData和NSDirctionary很相似了。


四、對多個對象進行解檔操做

NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
//讀取歸檔數據
NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];

//建立解歸檔對象,對data中的數據進行解歸檔
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

//解歸檔
NSArray *array = [unarchiver decodeObjectForKey:@"array"];
NSLog(@"%@",array);

int value = [unarchiver decodeObjectForKey:@"scope"];
NSLog(@"%d",value);
咱們能夠將文件解檔出一個NSData對象,而後能夠經過key去獲取指定的類型對象


2、自定義類型的歸檔和解檔

上面說到了已有類型的歸檔和解檔,下面來看一下自定義類型的歸檔和解檔操做,在開始的時候也說了,若是自定義的類型能夠進行歸檔和解檔的話,必須實現一個協議:NSCoding

很少說了,下面來直接看代碼解釋:

Person.h

//
//  Person.h
//  34_ArchiveProtocol
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//

#import <Foundation/Foundation.h>

//類只有實現NSCoding協議才能歸檔
@interface Person : NSObject<NSCoding>

@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger age;
@property(nonatomic,retain)NSArray *apples;

- (NSString *)description;

@end
這裏自定義了一個Person類型,實現了NSCoding協議,而後他有三個屬性,這裏咱們看到有新的方法去定義屬性,這個後面說到內存管理的時候在詳細說明。


Person.m

//
//  Person.m
//  34_ArchiveProtocol
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//

#import "Person.h"

@implementation Person

//解歸檔的時候調用
//也是一個初始化方法
- (id)initWithCoder:(NSCoder *)aDecoder{
    NSLog(@"initWithCoder");
    self = [super init];
    if(self != nil){
        /*
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeObjectForKey:@"age"];
        _apples = [aDecoder decodeObjectForKey:@"apples"];
         */
        //通常咱們將key定義成宏,這樣就不會出錯
        _name = [[aDecoder decodeObjectForKey:@"name"] copy];
        self.age = [aDecoder decodeObjectForKey:@"age"];
        self.apples = [aDecoder decodeObjectForKey:@"apples"];
        
    }
    return self;
}

//歸檔時調用此方法
- (void)encodeWithCoder:(NSCoder *)aCoder{
    NSLog(@"encodeWithCoder");
    [aCoder encodeObject:_name forKey:@"name"];//通常key和屬性名是取同樣的
    [aCoder encodeInteger:_age forKey:@"age"];
    [aCoder encodeObject:_apples forKey:@"apples"];
}

- (NSString *)description{
    NSString *string = [NSString stringWithFormat:@"name=%@,age=%d,apples=%@",_name,_age,_apples];
    return string;
}

@end
在Person.m文件中,咱們須要實現協議中的兩個方法:

initWithCoder

encodeWithCoder

這兩個方法一個是用於歸檔操做時會調用的方法,還有一個是用於解檔操做時會調用的方法

一、解檔的時候用到的方法

- (id)initWithCoder:(NSCoder *)aDecoder{
    NSLog(@"initWithCoder");
    self = [super init];
    if(self != nil){
        /*
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeObjectForKey:@"age"];
        _apples = [aDecoder decodeObjectForKey:@"apples"];
         */
        //通常咱們將key定義成宏,這樣就不會出錯
        _name = [[aDecoder decodeObjectForKey:@"name"] copy];
        self.age = [aDecoder decodeObjectForKey:@"age"];
        self.apples = [aDecoder decodeObjectForKey:@"apples"];
        
    }
    return self;
}
這個是一個初始化的方法,同時他也是一個解檔操做時會調用的方法,因此在這裏咱們既要寫一下初始化方法的特定代碼,還要寫上解檔的代碼,這裏主要看解檔的代碼

其實很簡單,就是對屬性從新寫一下值,而後對每一個屬性指定一個key就能夠了。這個有點相似於Android中的Parcel

(這裏咱們看到,在解檔name屬性的時候,用到了copy的一個方法,這個在後面會說到,有淺拷貝和深拷貝之分)


二、歸檔的時候用到的方法

//歸檔時調用此方法
- (void)encodeWithCoder:(NSCoder *)aCoder{
    NSLog(@"encodeWithCoder");
    [aCoder encodeObject:_name forKey:@"name"];//通常key和屬性名是取同樣的
    [aCoder encodeInteger:_age forKey:@"age"];
    [aCoder encodeObject:_apples forKey:@"apples"];
}
歸檔和解檔的操做正好相反的,可是要注意的是:他們屬性的key必定要保持一致


三、重寫description方法

- (NSString *)description{
    NSString *string = [NSString stringWithFormat:@"name=%@,age=%d,apples=%@",_name,_age,_apples];
    return string;
}
在以前的文章中我說道過,咱們在使用NSLog方法打印對象的值的時候,實際上是調用對象的description方法,而這個方法是NSObject類中的,咱們能夠重寫他,這樣咱們就能夠打印咱們想要的信息了。和Java中的toString方法同樣。


下面就來看一下使用方法了

main.m

//
//  main.m
//  34_ArchiveProtocol
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        p.name = @"張三";
        p.age = 20;
        p.apples = @[@"iphone",@"ipad"];
        
        //歸檔
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"person.archiver"];
        BOOL success = [NSKeyedArchiver archiveRootObject:p toFile:filePath];
        if(success){
            NSLog(@"歸檔成功");
        }
        
        //解歸檔
        Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
        NSLog(@"%@",person);
        
        
    }
    return 0;
}
咱們能夠看到,使用起來是很簡單的和上面的方式同樣,運行結果:


看到了,咱們自定義的description方法,打印了咱們本身想要的結果~~


總結

這一篇文章咱們就說了OC中的歸檔和解檔的相關概念和操做,其實說白了就是將對象寫入到文件,和從文件中讀取對象。

相關文章
相關標籤/搜索