iOS-NSCoder 和 NSCoding

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS-NSCoder 和 NSCoding相关的知识,希望对你有一定的参考价值。

1、ios提供基本的文件API、Property List序列化、SQLite、CoreData以及NSCoding,将应用数据存储到硬盘中。

对于轻量级的数据要求,NSCoding因其简单而成为一种比较合适的方式。 NSCoding是一个你需要在数据类上要实现的协议以支持数据类和数据流间的编码和解码。数据流可以持久化到硬盘。

2、是类对象本身数据的写入到本地文件。

一、NSCoder

NSCoder 是一个抽象类,抽象类不能被实例话,只能提供一些子类继承的方法。
NSKeyedUnarchiver 从二进制流读取对象。
NSKeyedArchiver 把对象写到二进制流中去。

二、NScoding

NScoding 是一个协议,主要有下面两个方法: encodeWithCoder和initWithEncoder。

// 解档方法(从coder中读取数据,保存到相应的变量中,即反序列化数据;实现NScoding协议)
- (instancetype)initWithCoder:(NSCoder *)coder;

// 归档调用方法(读取实例变量,并把这些数据写到coder中去,即序列化数据)
- (void)encodeWithCoder:(NSCoder *)coder;

encodeWithCoder就是编码,initWithCoder就是解码。 encodeWithCoder方法传入的是一个NSCoder对象,实现的时候我们就可以调用encodeObject、encodeFloat、 encodeInt等各种方法并通过指定键值进行编码。

示例代码如下:

Person.h文件

//Person.h文件
@interface Person : NSObject<NSCoding>

@property (nonatomic, assign)int ID;
@property (nonatomic, copy)NSString *card;
@property (nonatomic, assign)int age;
@property (nonatomic, copy)NSString *pName;
@property (nonatomic, strong)NSDecimalNumber *money;
@property (nonatomic, strong)NSMutableDictionary *dict;
@property (nonatomic, strong)NSMutableArray *arr;

@end

Person.m文件 

#import <objc/message.h> //包含消息机制

@implementation Person

// 设置不需要归解档的属性
- (NSArray *)ignoredNames {
    return @[@"ID",@"card"];
}

// 解档方法(从coder中读取数据,保存到相应的变量中,即反序列化数据;实现NScoding协议)
- (instancetype)initWithCoder:(NSCoder *)coder {
    if (self == [super init]) {
        // 获取所有成员变量
        unsigned int outCount = 0;
        Ivar *ivars = class_copyIvarList([self class], &outCount);
        
        for (int i = 0; i < outCount; i++) {
            Ivar ivar = ivars[i];
            // 将每个成员变量名转换为NSString对象类型
            NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
            
            // 忽略不需要解档的属性
            if ([[self ignoredNames] containsObject:key]) {
                continue;;
            }
            
            // 根据变量名解档取值,无论是什么类型
            id value = [coder decodeObjectForKey:key];
            // 取出的值再设置给属性
            [self setValue:value forKey:key];
            // 这两步就相当于以前的 self.age = [aDecoder decodeObjectForKey:@"_age"];
        }
        //释放内存!
        free(ivars);
    }
    return self;
}

// 归档调用方法(读取实例变量,并把这些数据写到coder中去,即序列化数据)
- (void)encodeWithCoder:(NSCoder *)coder {
    // 获取所有成员变量
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([self class], &outCount);
    for (int i = 0; i < outCount; i++) {
        Ivar ivar = ivars[i];
        // 将每个成员变量名转换为NSString对象类型
        NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
        
        // 忽略不需要归档的属性
        if ([[self ignoredNames] containsObject:key]) {
            continue;
        }
        
        // 通过成员变量名,取出成员变量的值
        id value = [self valueForKeyPath:key];
        // 再将值归档
        [coder encodeObject:value forKey:key];
        // 这两步就相当于 [aCoder encodeObject:@(self.age) forKey:@"_age"];
    }
    //释放内存!
    free(ivars);
}

注意:

类直接继承自NSObject

1、- (instancetype)initWithCoder:(NSCoder *)coder方法中无需调用[super initWithCoder:coder],直接调用[super init]即可

2、- (void)encodeWithCoder:(NSCoder *)coder方法中不用调用super方法

以上是关于iOS-NSCoder 和 NSCoding的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 NSCoding 保存结构

Swift,NSCoding 保存类的数组不起作用

使用 NSCoding 创建一个类

将 Codable 保存到 UserDefaults 并匹配 NSCoding 的外观

initWithCoder:被 nib 和 NSCoding 调用!

NSCoding 帮助非常奇怪的错误访问解除分配的实例