美文网首页iOS 开发
iOS NSSecureCoding 数据归档编码解码

iOS NSSecureCoding 数据归档编码解码

作者: T_aa | 来源:发表于2016-06-03 17:34 被阅读1288次


    基础太差...

    一点一点来...

    现在还不晚...


    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

    ----



    相关文章

      网友评论

      • 我本善良:楼主:感谢分享。decodeObjectOfClass:class forkey:key,查看文档应该是检测这个key解档后的对象的类型是否是我们指定的class吧。我测试的一个类People继承NSObject,实现NSSecureCoding协议:实现了supportsSecureCoding和decodeObjectOfClass:forkey:,有个属性是name,String类型;第一次存储我把一个people实例对象归档到本地;然后修改代码中的People类name的类型为NSData,也修改了self.name = [aDecoder decodeObjectOfClass:[NSData class] forKey:Key_Name];再次从本地读取刚刚存储的对象,依然能正常赋值;为什么没有报异常呢?本地的name应该是上次存储的NSString类型,而现在代码中People的name已经修改为NSData类型了,望解答一下。

      本文标题:iOS NSSecureCoding 数据归档编码解码

      本文链接:https://www.haomeiwen.com/subject/fctldttx.html