iOS NSSecureCoding 数据归档编码解码


基础太差...

一点一点来...

现在还不晚...


NSSecureCoding继承NSCoding...

数据归档过程多了数据类型检验...

相对更安全一点...


使用NSSecureCoding...

需要实现...

+(BOOL)supportsSecureCoding

/** 编码*/

-(instancetype)initWithCoder:(NSCoder *)aDecoder

/** 解码*/

-(void)encodeWithCoder:(NSCoder *)aCoder


多secure coding笔coding多一个传一个类型判断...

基本类型可以转成NSValue,或者NSNumber...

在编码initWithCoder中,设置每一个属性的编码...

self.dataList = [aDecoder decodeObjectOfClass:[NSMutableArray class] forKey:@"dataList"];

self.secureTitle = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secureTitle"];

self.secureIndex = [[aDecoder decodeObjectOfClass:[NSNumber class] forKey:@"secureIndex"] integerValue];

self.superObj = [aDecoder decodeObjectOfClass:[SecureObj class] forKey:@"superObj"];

self.secureContent  = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secureContent"];


在编码encodeWithCoder中,解码获取相应的值...

[aCoder encodeObject:self.dataList forKey:@"dataList"];

[aCoder encodeObject:self.secureTitle forKey:@"secureTitle"];

[aCoder encodeObject:self.superObj forKey:@"superObj"];

[aCoder encodeObject:@(self.secureIndex) forKey:@"secureIndex"];

[aCoder encodeObject:self.secureContent forKey:@"secureContent"];


基本设置好了之后...

开始使用...

/** 归档成data 直接传到服务端、或者本地存储*/

+ (NSData *)archivedDataWithRootObject:(id)rootObject;

/** 直接存本地路劲path*/

+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;


假设将存在本地沙盒...

路劲...

- (NSString *)pathArchive

{

NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

path = [path stringByAppendingPathComponent:@"archive"];

NSLog(@"###### %@",path);

return path;

}

通过NSKeyedArchiver 开始 archive...

SecureObj * obj = [SecureObj new];

obj.secureTitle = self.titleField.text;

obj.secureContent = self.contentTextView.text;

[NSKeyedArchiver archiveRootObject:obj toFile:[self pathArchive]];

通过NSKeyedUnarchiver 开始 unarchive...

SecureObj * obj = [NSKeyedUnarchiver unarchiveObjectWithFile:[self pathArchive]];

self.titleField.text = obj.secureTitle;

self.contentTextView.text = obj.secureContent;


但是有一个问题...

我们如果加一个属性...

都要去设置一遍decode,encode...

如果需要更懒,一步设置...

知道所有属性的名字...

对应属性的数据类型...

通过runtime可以对属性进行很多操作...

用到哪学到哪...

通过runtime获取类中属性的列表....

///通过运行时获取当前对象的所有属性的名称,以数组的形式返回

- (NSArray *) allPropertyNames{

///存储所有的属性名称

NSMutableArray *allNames = [[NSMutableArray alloc] init];

///存储属性的个数

unsigned int propertyCount = 0;

///通过运行时获取当前类的属性

objc_property_t *propertys = class_copyPropertyList([self class], &propertyCount);

//把属性放到数组中

for (int i = 0; i < propertyCount; i ++) {

///取出第一个属性

objc_property_t property = propertys[i];

const char * propertyName = property_getName(property);

[allNames addObject:[NSString stringWithUTF8String:propertyName]];

}

///释放

free(propertys);

return allNames;

}

获取属性的数据类型信息...

NSMutableDictionary * dictionary = objc_getAssociatedObject([self class], _cmd);

if(dictionary)

{

return dictionary;

}

dictionary = [NSMutableDictionary dictionary];

Class subClass = [self class];

while (subClass != [NSObject class] && subClass)

{

unsigned int propertyCount;

objc_property_t * properties = class_copyPropertyList([self class], &propertyCount);

for(int i = 0; i < propertyCount; i++)

{

objc_property_t property = properties[i];

const char * propertyName = property_getName(property);

NSString * key = @(propertyName);

char * ivar = property_copyAttributeValue(property, "V");

if(ivar)

{

NSString *ivarName = @(ivar);

if ([ivarName isEqualToString:key] ||

[ivarName isEqualToString:[@"_" stringByAppendingString:key]])

{

Class propertyClass = nil;

char *typeEncoding = property_copyAttributeValue(property, "T");

switch (typeEncoding[0])

{

case 'c': // Numeric types

case 'i':

case 's':

case 'l':

case 'q':

case 'C':

case 'I':

case 'S':

case 'L':

case 'Q':

case 'f':

case 'd':

case 'B':

{

propertyClass = [NSNumber class];

break;

}

case '*': // C-String

{

propertyClass = [NSString class];

break;

}

case '@': // Object

{

NSString * classStr = @(typeEncoding);

classStr = [classStr stringByReplacingOccurrencesOfString:@"@" withString:@""];

classStr = [classStr stringByReplacingOccurrencesOfString:@"\"" withString:@""];

classStr = [classStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];

propertyClass = NSClassFromString(classStr);

break;

}

case '{': // Struct

{

propertyClass = [NSValue class];

break;

}

case '[': // C-Array

case '(': // Enum

case '#': // Class

case ':': // Selector

case '^': // Pointer

case 'b': // Bitfield

case '?': // Unknown type

default:

{

propertyClass = nil; // Not supported by KVC

break;

}

}

free(typeEncoding);

// If known type, add to dictionary

if (propertyClass)

{

dictionary[key] = propertyClass;

}

}

}

free(ivar);

subClass = [subClass superclass];

}

objc_setAssociatedObject([self class], _cmd, dictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

return dictionary;


在decode时候...

[[self getPropertyClassesByName] enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull propertyClass, BOOL * _Nonnull stop) {

id object = [aDecoder decodeObjectOfClass:propertyClass forKey:key];

if (object)

{

[self setValue:object forKey:key];

}

}];

encode...

for (NSString *key in [self getPropertyClassesByName])

{

id object = [self valueForKey:key];

if (object)

{

[aCoder encodeObject:object forKey:key];

}

}




以上仅代表个人观点...

有错误欢迎指出...

源码地址...



参考资料:

数据持久化(归档反归档)

runtime



----



你可能感兴趣的:(iOS NSSecureCoding 数据归档编码解码)