zoukankan      html  css  js  c++  java
  • iOS数据持久化存储:归档

    在平时的iOS开发中,我们经常用到的数据持久化存储方式大概主要有:NSUserDefaults(plist),文件,数据库,归档。。前三种比较经常用到,第四种归档我个人感觉用的还是比较少的,恰恰因为用的比较少,但是还是有地方要用到,所以今天再把归档解档复习一遍吧。

    一、什么是归档:

      对象归档是将对象以文件的形式保存到磁盘中(也称为序列化,持久化) ;使用的时候读取该文件的保存路径读取文件的内容(也称为解档,反序列化)

    二、归档 与 plist存储的区别:

    • 对象归档的文件是保密的,在磁盘上无法查看文件中的内容,而plist属性列表是明文的可以查看。
    • 其次就是保存的数据类型不同
      • 只要是对象类型,归档都可以保存。
      • 而plist只能保存这几种类型:NSString  NSNumber  NSDate NSData NSArray NSDictionary  。不能保存其他的类型

    三、归档的使用

      刚刚说到,只要是对象类型,都可以用归档的方式进行保存。

      但是,只有实现了<NSCoding>协议的类型才可以进行归档,由于Foudation框架中的对象类型已经实现了NSCoding协议,所以可以直接归档解档,而我们自定义的类型,则需要我们手动去实现NSCoding协议。必须实现一下两个方法:

    //归档的时候调用的方法
    - (void)encodeWithCoder:(NSCoder *)aCoder;
    //解归档的时候要调用的函数
    - (id)initWithCoder:(NSCoder *)aDecoder;

      1.对系统类的归档:

        第一种方式:单个对象的归档和解档

    //单个对象归档:
        NSArray *array1 = @[@"zhangsan",@"wangwu",@"lisi"];
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
        BOOL success = [NSKeyedArchiver archiveRootObject:array1 toFile:filePath];
        if (success) {
            NSLog(@"保存成功!");
        }
        //单个对象解档
        id array2 =  [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
        NSLog(@"%@",array2);

        第二种方式:多个对象的归档和解档

        //多个对象归档:
        NSArray *array1 = @[@"zhangsan",@"wangwu",@"lisi"];
        NSMutableData *data = [NSMutableData data];
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
        //编码
        [archiver encodeObject:array1 forKey:@"array"];
        [archiver encodeInt:100 forKey:@"scope"];
        [archiver encodeObject:@"jack" forKey:@"name"];
        //完成编码,讲上面的归档数据填充到data中,此时data已经存储了归档对象的数据
        [archiver finishEncoding];
        NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
        BOOL success = [data writeToFile:filePath atomically:YES];
        if (success) {
            NSLog(@"归档成功");
        }
        
        //多个对象解档
        NSData *data2 = [[NSData alloc] initWithContentsOfFile:filePath];
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data2];
        NSArray *array = [unarchiver decodeObjectForKey:@"array"];
        NSLog(@"%@",array);
        int value = [unarchiver decodeIntForKey:@"scope"];
        NSLog(@"%d",value);
      [unarchiver finishDecoding];


      2.自定义类型的归档解档

      上面已经说过了,对系统类型可以直接进行归档和解档,但是对于自定义类型,必须实现NSCoding协议

    #import <Foundation/Foundation.h>
    #import "Car.h"
    
    int main(int argc, const char * argv[])
    {
        /*
         有辆汽车 有一个引擎 和 四个轮胎
         
         然后需要对这个汽车进行归档 本地保存数据
         这时 还必须要对汽车的引擎和轮胎也要归档
         
         只要有成员变量是对象地址 都要继续归档 
         
         那么这时归档的类 都要遵守协议NSCoding 实现里面的方法
         
         实际上 归档就是一个深拷贝
         */
        
        @autoreleasepool {
         
    #if 0
            Car *BMW = [[Car alloc] init];
            BMW.speed = 100;
            [BMW run];
            
            //程序结束之前把汽车对象的信息进行保存到本地
            //归档
            
            NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"car.src"];
            
            BOOL ret = [NSKeyedArchiver archiveRootObject:BMW toFile:filePath];
            if (ret) {
                NSLog(@"汽车对象归档成功");
            }else {
                NSLog(@"汽车归档失败");
            }
            [BMW release];
            
    #else
            //解归档-->从文件中获取数据创建一个Car对象
            
            NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"car.src"];
    
            Car *car = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
            
            NSLog(@"car.speed:%ld",car.speed);
            NSLog(@"engine.name:%@",car.engine.name);
            [car run];
        
    #endif
            
        }
        return 0;
    }

      汽车类:

    #import <Foundation/Foundation.h>
    #import "Engine.h"
    #import "Tyre.h"
    
    //遵守归档协议
    @interface Car : NSObject<NSCoding>
    {
        Engine *_engine;
        NSMutableArray *_tyresArr;
        NSInteger _speed;
    }
    @property (nonatomic) NSInteger speed;
    @property (nonatomic,retain) Engine *engine;
    - (Car *)init;
    - (void)run;
    @end
    #import "Car.h"
    
    @implementation Car
    - (void)dealloc {
        NSLog(@"汽车销毁");
        [_engine release];
        [_tyresArr release];
        [super dealloc];
    }
    
    //对Car归档的时候会调用的方法
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        //就是对成员变量的数据进行归档
        //如果成员变量是基本类型 那么直接归档
        //如果成员变量变量是对象地址 那么对象的类也要遵守协议实现方法
        
        //在类中 如果有setter和getter方法那么尽量使用setter和getter方法
        [aCoder encodeInteger:self.speed forKey:@"speed"];
        //对一个对象地址指向的对象进行归档 那么指向对象也要实现归档协议的方法 Engine 要遵守 数组要遵守 数组的元素也要遵守
        [aCoder encodeObject:self.engine forKey:@"engine"];
        [aCoder encodeObject:_tyresArr forKey:@"array"];
    }
    //对象解归档、读档的时候调用
    - (id)initWithCoder:(NSCoder *)aDecoder {
        if (self = [super init]) {//如果父类有initWithCoder那么调用父类的initWithCoder:
            
            //这里不要直接写 成员变量 否则就有可能崩溃
            //要用setter方法 这样 内部会计数器+1 拥有绝对使用权
            //读档
            self.engine = [aDecoder decodeObjectForKey:@"engine"];
            NSLog(@"%ld",self.engine.retainCount);
            self.speed = [aDecoder decodeIntegerForKey:@"speed"];
            //要注意拥有绝对使用权
            _tyresArr = [[aDecoder decodeObjectForKey:@"array"] retain];
            
        }
        return self;
    }
    
    
    
    - (Car *)init {
        if (self = [super init]) {
            _engine = [[Engine alloc] init];
            _engine.name = @"德国";
            _engine.power = 1000;
            
            _tyresArr = [[NSMutableArray alloc] init];
            for (int i = 0; i < 4; i++) {
                Tyre *tyre = [[Tyre alloc] init];
                tyre.name = @"米其林";
                tyre.type = 12345;
                [_tyresArr addObject:tyre];
                [tyre release];
            }
        }
        return self;
    }
    - (void)run {
        NSLog(@"汽车跑");
        [self.engine start];
        for (Tyre *tyre in _tyresArr) {
            [tyre scroll];//滚动
        }
    }
    
    @end

    轮胎类:

    #import <Foundation/Foundation.h>
    
    @interface Tyre : NSObject<NSCoding>
    {
        NSString *_name;
        NSInteger _type;
    }
    @property (nonatomic,copy)NSString *name;
    @property (nonatomic)NSInteger type;
    - (void)scroll;
    
    @end
    #import "Tyre.h"
    
    @implementation Tyre
    - (void)dealloc {
        NSLog(@"轮胎销毁");
        self.name = nil;
        [super dealloc];
    }
    //归档调用
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        [aCoder encodeObject:self.name forKey:@"name"];
        [aCoder encodeInteger:self.type forKey:@"type"];
    }
    //读档调用
    - (id)initWithCoder:(NSCoder *)aDecoder {
        if (self = [super init]) {
            //用setter方赋值 内部有计数器+1 
            self.name = [aDecoder decodeObjectForKey:@"name"];
            self.type = [aDecoder decodeIntegerForKey: @"type"];
        }
        return self;
    }
    
    
    - (void)scroll {
        NSLog(@"%@ 轮胎在滚动",self.name);
    }
    @end

    引擎类:

    #import <Foundation/Foundation.h>
    
    @interface Engine : NSObject <NSCoding>
    {
        NSString *_name;
        NSInteger _power;
    }
    @property (nonatomic,copy)NSString *name;
    @property (nonatomic) NSInteger power;
    - (void)start;
    @end
    #import "Engine.h"
    
    @implementation Engine
    - (void)dealloc {
        NSLog(@"引擎销毁");
        self.name = nil;
        [super dealloc];
    }
    //归档调用
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        [aCoder encodeObject:self.name forKey:@"name"];
        [aCoder encodeInteger:self.power forKey:@"power"];
    }
    //读档调用
    - (id)initWithCoder:(NSCoder *)aDecoder {
        if (self = [super init]) {
            self.name = [aDecoder decodeObjectForKey:@"name"];
            self.power = [aDecoder decodeIntegerForKey: @"power"];
        }
        return self;
    }
    
    - (void)start {
        NSLog(@"引擎启动");
    }
    @end
     
     
  • 相关阅读:
    关于TCP/IP协议栈
    关于java socket
    批处理的高吞吐率和高延迟的解释
    关于Xmanager使用问题的总结
    关于Storm Stream grouping
    django url 传递多个参数
    多线程 python threading 信号量/递归锁
    多线程 python threading 简单锁/互斥锁
    django 1.9 wsgi + nginx
    django models ForeignKey Many-to-ManyField 操作
  • 原文地址:https://www.cnblogs.com/wuqh-iOS/p/4846811.html
Copyright © 2011-2022 走看看