NSCoding对象存储(注意:以后使用NSSecureCoding)

1. NSCoding是一个协议,遵守NSCoding协议的类,可以实现这个类到NSData的互相转换

2. 使用场景

  • NSUserDefaults 将自定义的类转换成NSData实例,然后存储到偏好存储中。
  • 文件存储 :NSData类提供了一个方法,可以直接将NSData实例存储到文件中

3. 相关知识介绍

  • NSCoder类是一个抽象类,用来被其他的类继承
  • NSKeyedArchiver 和 NSKeyedUnarchiver,NSKeyedArchiver将自定义的类转换成NSData实例,类里面每一个值对应一个Key;NSKeyedUnarchiver将NSData实例根据key值还原成自定义的类。
  • NSCoding 和 NSSecureCoding,NSCoding安全性不高,所以iOS6的时候,苹果引入了NSSecureCoding协议,加强安全性。
  • NSSecureCoding:存取方法一定要使用NSSecureCoding的。

4. 代码实现NSSecureCoding

//
//  MyDog.h
//  NSSecureCoding

#import <Foundation/Foundation.h>

@interface MyDog : NSObject<NSSecureCoding>
@property(nonatomic, strong) NSString *name;
@property(nonatomic, assign) NSInteger age;
@end
//
//  MyDog.m
//  NSSecureCoding

#import "MyDog.h"

@implementation MyDog

+ (BOOL)supportsSecureCoding {
    return YES; //支持加密编码
}

//解码方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        if (aDecoder) {
            _name = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"name"];
            _age = [aDecoder decodeIntegerForKey:@"age"];
        }
    }
    return self;
}

//编码方法
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
}
@end
//
//  ViewController.m
//  NSSecureCoding

#import "ViewController.h"
#import "MyDog.h"
@interface ViewController ()

@property(nonatomic, strong)NSData *archivedData;
- (IBAction)archiveObject:(id)sender;
- (IBAction)UnArchiveObject:(id)sender;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)archiveObject:(id)sender {
    //MyDog -> NSData
    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
    //设置安全加密
    [archiver setRequiresSecureCoding:YES];
    //开始编码
    MyDog *dog = [[MyDog alloc]init];
    dog.name = @"泰迪";
    dog.age = 2;
    
    [archiver encodeObject:dog forKey:NSKeyedArchiveRootObjectKey];
    //结束编码
    [archiver finishEncoding];
    
    _archivedData = [data copy];
}

- (IBAction)UnArchiveObject:(id)sender {
    //NSData -> MyDog
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:_archivedData];
    [unarchiver setRequiresSecureCoding:YES];
    MyDog *dog = [unarchiver decodeObjectOfClass:[MyDog class] forKey:NSKeyedArchiveRootObjectKey];
    NSLog(@"%@ %ld",dog.name,(long)dog.age);
}
@end

5. 增加分类,更加方便的解码编码

增加分类时New File -> Objective-C File
File Type选择分类Category
Class 解码的选择NSKeyedUnarchiver 编码的选择NSKeyedArchiver

//
//  NSKeyedArchiver+ConvertNSData.h
//  NSSecureCoding

#import <Foundation/Foundation.h>

@interface NSKeyedArchiver (ConvertNSData)

+ (NSData *)dataWithCustomClass:(id<NSSecureCoding>)customClassObject;

@end
//
//  NSKeyedArchiver+ConvertNSData.m
//  NSSecureCoding

#import "NSKeyedArchiver+ConvertNSData.h"

@implementation NSKeyedArchiver (ConvertNSData)

+ (NSData *)dataWithCustomClass:(id<NSSecureCoding>)customClassObject {
    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
    [archiver setRequiresSecureCoding:YES];
    [archiver encodeObject:customClassObject forKey:NSKeyedArchiveRootObjectKey];
    [archiver finishEncoding];
    return data;
}

@end
//
//  NSKeyedUnarchiver+ConvertNSData.h
//  NSSecureCoding

#import <Foundation/Foundation.h>

@interface NSKeyedUnarchiver (ConvertNSData)

+ (id<NSSecureCoding>)customInstanceFromData:(NSData *)data ForClass:(Class)classType;

@end
//
//  NSKeyedUnarchiver+ConvertNSData.m
//  NSSecureCoding

#import "NSKeyedUnarchiver+ConvertNSData.h"

@implementation NSKeyedUnarchiver (ConvertNSData)

+ (id<NSSecureCoding>)customInstanceFromData:(NSData *)data ForClass:(Class)classType {
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
    [unarchiver setRequiresSecureCoding:YES];
    
    return [unarchiver decodeObjectOfClass:[classType class] forKey:NSKeyedArchiveRootObjectKey];
}

@end
//
//  MyDog.h
//  NSSecureCoding

#import <Foundation/Foundation.h>

@interface MyDog : NSObject<NSSecureCoding>
@property(nonatomic, strong) NSString *name;
@property(nonatomic, assign) NSInteger age;
@end
//
//  MyDog.m
//  NSSecureCoding

#import "MyDog.h"

@implementation MyDog

+ (BOOL)supportsSecureCoding {
    return YES; //支持加密编码
}

//解码方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        if (aDecoder) {
            _name = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"name"];
            _age = [aDecoder decodeIntegerForKey:@"age"];
        }
    }
    return self;
}

//编码方法
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
}
@end
//
//  ViewController.m
//  NSSecureCoding

#import "ViewController.h"
#import "MyDog.h"
#import "NSKeyedArchiver+ConvertNSData.h"
#import "NSKeyedUnarchiver+ConvertNSData.h"
@interface ViewController ()

@property(nonatomic, strong)NSData *archivedData;
- (IBAction)archiveObject:(id)sender;
- (IBAction)UnArchiveObject:(id)sender;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)archiveObject:(id)sender {
    //MyDog -> NSData
    //开始编码
    MyDog *dog = [[MyDog alloc]init];
    dog.name = @"泰迪";
    dog.age = 2;
    
    _archivedData = [NSKeyedArchiver dataWithCustomClass:dog];
}

- (IBAction)UnArchiveObject:(id)sender {
    //NSData -> MyDog
    MyDog *dog = (MyDog *)[NSKeyedUnarchiver customInstanceFromData:_archivedData ForClass:[MyDog class]];
    NSLog(@"%@ %ld",dog.name,(long)dog.age);
}
@end

推荐阅读更多精彩内容