归档NSSecureCoding的使用

NSCoding是一种非安全的编解码方式,使用NSKeyedArchiver归档自定义类对象做持久化存储。由于未做数据校验,可通过篡改本地存储的信息进行攻击。从IOS 6.0之后引入了NSSecureCoding来保证数据安全。

NSSecureCoding协议继承自NSCoding,有着比NSCoding更加安全的编码和解码。

在iOS 12.0以后,仅保留了两个方法

/**
 Initializes the receiver for encoding an archive, optionally disabling secure coding.

 If \c NSSecureCoding cannot be used, \c requiresSecureCoding may be turned off here; for improved security, however, \c requiresSecureCoding should be left enabled whenever possible. \c requiresSecureCoding ensures that all encoded objects conform to \c NSSecureCoding, preventing the possibility of encoding objects which cannot be decoded later.

 To produce archives whose structure matches those previously encoded using \c +archivedRootDataWithObject, encode the top-level object in your archive for the \c NSKeyedArchiveRootObjectKey.
 */
- (instancetype)initRequiringSecureCoding:(BOOL)requiresSecureCoding API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/**
 Returns an \c NSData object containing the encoded form of the object graph whose root object is given, optionally disabling secure coding.

 If \c NSSecureCoding cannot be used, \c requiresSecureCoding may be turned off here; for improved security, however, \c requiresSecureCoding should be left enabled whenever possible. \c requiresSecureCoding ensures that all encoded objects conform to \c NSSecureCoding, preventing the possibility of encoding objects which cannot be decoded later.

 If the object graph cannot be encoded, returns \c nil and sets the \c error out parameter.
 */
+ (nullable NSData *)archivedDataWithRootObject:(id)object requiringSecureCoding:(BOOL)requiresSecureCoding error:(NSError **)error API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

使用步骤:
1、遵守协议NSSecureCoding

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface FLPersion : NSObject <NSSecureCoding>

/** 姓名*/
@property (strong, nonatomic) NSString *name;
/** 年龄*/
@property (assign, nonatomic) int age;
@end

NS_ASSUME_NONNULL_END

2、实现协议方法
和NSCoding相比,必须实现一个+ (BOOL)supportsSecureCoding方法,返回YES,表示支持SecureCoding。

重写了 -initWithCoder 的类应该使用 -decodeObjectOfClass:forKey:而不是-decodeObjectForKey:

设置每一个属性的编码和解码获取相应的值

#import "FLPersion.h"

@implementation FLPersion
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInt:self.age forKey:@"age"];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        self.name = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"name"];
        self.age = [aDecoder decodeIntForKey:@"age"];
    }
    return self;
}

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

@end

3、实现存取

#import "ViewController.h"
#import "FLPersion.h"

@interface ViewController ()
/** 校验数据*/
@property (strong, nonatomic) NSData *archivedData;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)archiver:(id)sender {
    //开始编码
    FLPersion *per = [[FLPersion alloc]init];
    per.name = @"zhangsan";
    per.age = 28;

    NSError *error = nil;
    self.archivedData = [NSKeyedArchiver archivedDataWithRootObject:per requiringSecureCoding:YES error:&error];
    
    if (self.archivedData == nil || error) {
        NSLog(@"归档失败:%@", error);
        return;
    }
    
}

- (IBAction)unarchive:(id)sender {
    NSError *error = nil;
    FLPersion *per = [NSKeyedUnarchiver unarchivedObjectOfClass:[FLPersion class] fromData:self.archivedData error:&error];
    if (per == nil || error) {
        NSLog(@"解档失败:%@", error);
        return;
    }
    NSLog(@"%@ %ld",per.name,(long)per.age);
}

@end
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容