iOS数据持久化存储:归档

摘要:
在通常的iOS开发中,我们通常使用以下数据持久性存储方法:NSUserDefaults、文件、数据库和存档。。plist只能存储以下类型:NSStringNSNumberNSDateNSDataNSArray NSDictionary。

在平时的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
 
 

免责声明:文章转载自《iOS数据持久化存储:归档》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Mysql----浅入浅出之视图、存储过程、触发器Xcode 6 AutoLayout Size Classes下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Kubernetes 存储系统 Storage 介绍:PV,PVC,SC

要求:先了解数据docker容器中数据卷的挂载等知识参考网址: https://www.cnblogs.com/sanduzxcvbnm/p/13176938.html https://www.cnblogs.com/sanduzxcvbnm/p/13371254.html 容器中的存储都是临时的,因此Pod重启的时候,内部的数据会发生丢失。实际应用中...

CharacterController 中Move 和 SimpleMove的区别分析

CollisionFlagsMove(Vector3 motion); Description A more complex move function taking absolute movement deltas; Attempts to move the controller by mothon will only be constrained by...

前端实现大文件上传分片上传断点续传

总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块),但这不是我们现在说的重点,我们要做的事是保证在网络中断后1G的文件已上传的那部分在下次网络连接时不必再重传。所以我们本地在上传的时候,要将大文件...

Android持久化存储——(包含操作SQLite数据库)

《第一行代码》读书手札 你可能会遇到的问题:解决File Explorer 中无显示问题 Android中,持久化存储,常见的一共有三种方法实现 (一.)利用文件存储 文件存储是Android存储中,最基本的一种存储方式。 就是利用Context类的方法,获取输入输出字节流对象,之后,就是java的文件操作。 特点: 不对存储的数据进行任何格式...

基于七牛云对象存储,搭建一个自己专属的极简Web图床应用(手摸手的注释讲解核心部分的实现原理)

一个极简的Web图床应用,支持复制粘贴与拖拽上传图片 1.开发缘由 日常使用Vs Code编写markdown笔记与博客文章时,在文章中插入图片时发现非常不便 使用本地文件编写相对路径---没法直接复制粘贴到其它地方 使用第三方的图床---需要登录账号(还是放到自己"口袋"里放心) vs code内置插件--- 诸多bug使用不方便 喜欢折腾(真实)...

WKWebView-b

上一篇文章我们使用了JavaScriptCore框架重写了之前的示例,iOS8苹果偏爱HTML5,重构了UIWebVIew,给我们带来了WKWebView,使其性能、稳定性、功能大幅度提升,也更好的支持了HTML5的新特性。这篇文章就们就拿WKWebView来小试牛刀 回到顶部 一、WKWebView Framework WKWebView的14个类与...