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