NSCoding是一个协议,如果实现这个协议,就可以将这个类转换成NSData,并互相转换
使用场景1,NSUserDefaults存储数据时,需要转成NSData
使用场景2,因为NSData提供了一个方法来存储数据
NSCorder类是一个抽象类,用来被其他的类继承。
NSCorder定义了一些接口,使数据从内存到其他格式的转换。
NSKeyedArchiver和NSKeyedUnarchiver
NSKeyedArchiver将自定义类转化成NSData实例,类里面的每一个值对应一个key
NSKeyedUnarchiver将NSData实例根据key的值还原成自定义的类。
NSCoding和NSSecureCoding(iOS6以后)
NSCoding安全性不高,存储到rom中会被篡改
NSSecureCoding安全的,会进行类型检查,类型不匹配,就抛出异常。
具体代码实现地址:https://gitee.com/xgkp/NSSecureCodingDemoo.git
说明:
创建一个工程名字叫NSSecureCodingDemoo
创建一个类叫MyDog
MyDog.h中代码,注意这里的<NSSecureCoding>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MyDog : NSObject<NSSecureCoding>
@property (nonatomic,strong) NSString *name;
@property (nonatomic,assign) NSInteger age;
@end
NS_ASSUME_NONNULL_END
在MyDog.h中的代码
#import "MyDog.h"
@implementation MyDog
+(BOOL)supportsSecureCoding
{
return YES;
}
-(instancetype)initWithCoder:(NSCoder *)coder
{
if (self = [super init]) {
if (coder) {
_name = [coder decodeObjectOfClass:[NSString class] forKey:@"name"];
_age = [coder decodeIntegerForKey:@"age"];
}
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:_name forKey:@"name"];
[coder encodeInteger:_age forKey:@"age"];
}
@end
viewcontroller中的代码,注意这里的实现是在iOS13之后,demo的版本是在iOS13及以后的实现,部分方法如果在iOS12以前实现有所不同
#import "ViewController.h"
#import "MyDog.h"
@interface ViewController ()
@property (nonatomic,strong) NSData *archiveData;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)dogToData:(id)sender {
// myDog to nsdata
NSData * data = [NSMutableData data];
MyDog * dog = [[MyDog alloc] init];
dog.name = @"泰迪";
dog.age= 2;
NSError *error = nil;
data = [NSKeyedArchiver archivedDataWithRootObject:dog requiringSecureCoding:YES error:&error];
if (data == nil || error) {
NSLog(@"%@",error);
return;
}
_archiveData = [data copy];
}
- (IBAction)dataToDog:(id)sender {
// data -> mydog
NSError * error = nil;
MyDog * dog = [NSKeyedUnarchiver unarchivedObjectOfClass:[MyDog class] fromData:_archiveData error:&error];
NSLog(@"%@",dog.name);
NSLog(@"%ld",dog.age);
}
@end
在实际开发中可以直接使用category来实现NSKeyedUnarchiver+ConvertNSData
//
// NSKeyedUnarchiver+ConvertNSData.h
// NSSecureCodingDemoo
//
// Created by hpkj on 2020/1/19.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSKeyedUnarchiver (ConvertNSData)
+(id<NSSecureCoding>)customInstanceFromData:(NSData *)data ForClass:(Class)classType;
@end
NS_ASSUME_NONNULL_END
//
// NSKeyedUnarchiver+ConvertNSData.m
// NSSecureCodingDemoo
//
// Created by hpkj on 2020/1/19.
//
#import "NSKeyedUnarchiver+ConvertNSData.h"
@implementation NSKeyedUnarchiver (ConvertNSData)
+(id<NSSecureCoding>)customInstanceFromData:(NSData *)data ForClass:(Class)classType
{
NSError * error = nil;
return [NSKeyedUnarchiver unarchivedObjectOfClass:[classType class] fromData:data error:&error];
}
@end
Category的NSKeyedArchiver+ConvertNSData.h实现
//
// NSKeyedArchiver+ConvertNSData.h
// NSSecureCodingDemoo
//
// Created by hpkj on 2020/1/19.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSKeyedArchiver (ConvertNSData)
+(NSData *)dataWithCustomClass:(id<NSSecureCoding>)customClass;
@end
NS_ASSUME_NONNULL_END
//
// NSKeyedArchiver+ConvertNSData.m
// NSSecureCodingDemoo
//
// Created by hpkj on 2020/1/19.
//
#import "NSKeyedArchiver+ConvertNSData.h"
@implementation NSKeyedArchiver (ConvertNSData)
+(NSData *)dataWithCustomClass:(id<NSSecureCoding>)customClass
{
NSMutableData * data = [NSMutableData data];
NSError *error = nil;
data = [NSKeyedArchiver archivedDataWithRootObject:customClass requiringSecureCoding:YES error:&error];
return [data copy];
}
@end
总结:如果希望自定义类或者model数据类能够被存储到缓存中,可以将类的实现中加上NSSecureCoding协议的实现
网友评论