1. NSCoding是一個協(xié)議凑懂,遵守NSCoding協(xié)議的類,可以實現(xiàn)這個類到NSData的互相轉(zhuǎn)換
2. 使用場景
- NSUserDefaults 將自定義的類轉(zhuǎn)換成NSData實例阿宅,然后存儲到偏好存儲中。
- 文件存儲 :NSData類提供了一個方法笼蛛,可以直接將NSData實例存儲到文件中
3. 相關知識介紹
- NSCoder類是一個抽象類洒放,用來被其他的類繼承
- NSKeyedArchiver 和 NSKeyedUnarchiver,NSKeyedArchiver將自定義的類轉(zhuǎn)換成NSData實例滨砍,類里面每一個值對應一個Key往湿;NSKeyedUnarchiver將NSData實例根據(jù)key值還原成自定義的類。
- NSCoding 和 NSSecureCoding惋戏,NSCoding安全性不高领追,所以iOS6的時候,蘋果引入了NSSecureCoding協(xié)議响逢,加強安全性绒窑。
- NSSecureCoding:存取方法一定要使用NSSecureCoding的。
4. 代碼實現(xiàn)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