美文网首页RumeTime
runtime 自动归档

runtime 自动归档

作者: 天空中的球 | 来源:发表于2016-05-19 17:27 被阅读67次

    提到归档这块,首先得看了一下,常规的归档方法(又名序列化),把对象转为字节码,以文件的形式存储到磁盘上;程序运行过程中或者当再次重写打开程序的时候,可以通过解归档(反序列化)还原这些对象。

    注意NSCoding协议中有两个方法:

    • encodeWithCoder方法对对象属性进行编码,在对象归档时调用
    • initWithCoder方法解码归档数据来初始化对象,在对象解归档时调用
    #import <Foundation/Foundation.h>
    
    @interface UserModel : NSObject<NSCoding>
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    
    @end
    
    
    #import "UserModel.h"
    
    NSString *const kNameKey = @"name";
    NSString *const kAgeKey = @"age";
    
    @implementation UserModel
    
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        
        [aCoder encodeObject:self.name forKey:kNameKey];
        [aCoder encodeInteger:self.age forKey:kAgeKey];
    }
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        if (self == [super init]) {
            self.name = [aDecoder decodeObjectForKey:kNameKey];
            self.age = [aDecoder decodeIntegerForKey:kAgeKey];
        }
        return self;
    }
    
    @end
    

    //归档(序列化)

    // Content
    UserModel *model = [[UserModel alloc] init];
    model.name = @"Yang";
    model.age = 22;
    
    // save
    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:kYangPath];
    
    NSMutableData *archiverData = [NSMutableData data];
    NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiverData];
    [archiver encodeObject:model forKey:kYangKey];
    [archiver finishEncoding];
    
    
    if ([archiverData writeToFile:filePath atomically:YES]) {
        NSLog(@"archiver success");
    }
    

    //解归档(反序列化)

    //get
    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:kYangPath];
    NSData *unarchiverData = [NSData dataWithContentsOfFile:filePath];
    NSKeyedUnarchiver *unachiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:unarchiverData];
    UserModel *model = [unachiver decodeObjectForKey:kYangKey];
    NSLog(@"test name === %@,age === %lu",model.name,model.age);
    // output: test name === Yang,age === 22
    
    • 归档和解归档可以用于少量数据的持久化存储和读取
    • 属性列表只能存储Foundation框架中的对象,归档除了可以归档Foundation框架中的对象以外,还可以归档实现了NSCoding协议的自定义对象
    • 通过归档创建的文件是加密的
    然而我们为什么要使用runtime 进行归档呢?

    在上面model中,我们的类只有2个属性:name和age,于是我们在存档和解档的时候分别对这两个属性进行了处理,万一这个类的属性很多呢?!一个一个属性写的话,肯定是超级浪费时间的,所以此时runtime 就派上用场啦

    此时我们需要用到runtime 的一个优势,获取类中的所有成员属性,此处有两个方法。

    OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
    
    OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
    
    
    // 第一个参数:表示获取哪个类中的成员属性
    // 第二个参数:表示这个类有多少成员属性,传入一个Int变量地址,会自动给这个变量赋值
    
    
    

    注意class_copyPropertyList返回的仅仅是对象类的属性(@property申明的属性),而class_copyIvarList返回类的所有属性和变量(包括在@interface大括号中声明的变量),此处我们用第一种。(第二种方法也可以尝试)

    详细实现

    #import "BaseModel.h"
    #import <objc/runtime.h>
    
    @implementation BaseModel
    
    // 归档
    - (void)encodeWithCoder:(NSCoder *)enCoder{
        //归档存储自定义对象
        unsigned int count = 0;
        //获得指向该类所有属性的指针
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i =0; i < count; i ++) {
            //获得
            objc_property_t property = properties[i];
            //根据objc_property_t获得其属性的名称--->C语言的字符串
            const char *name = property_getName(property);
            NSString *key = [NSString stringWithUTF8String:name];
            // 编码每个属性,利用kVC取出每个属性对应的数值
            [enCoder encodeObject:[self valueForKeyPath:key] forKey:key];
        }
        free(properties);
    }
    
    
    // 解档
    - (id)initWithCoder:(NSCoder *)aDecoder{
        //归档存储自定义对象
        unsigned int count = 0;
        //获得指向该类所有属性的指针
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i =0; i < count; i ++) {
            objc_property_t property = properties[i];
            //根据objc_property_t获得其属性的名称--->C语言的字符串
            const char *name = property_getName(property);
            NSString *key = [NSString stringWithUTF8String:name];
            //解码每个属性,利用kVC取出每个属性对应的数值
            [self setValue:[aDecoder decodeObjectForKey:key] forKeyPath:key];
        }
        free(properties);
        return self;
    }
    
    @end
    
    然后其他类使用,只要继承它就好了
    #import "BaseModel.h"
    
    @interface PeopleModel : BaseModel
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    
    @end
    

    然后.m 中基本不需要做什么,然后就可以正常使用归档或解档啦
    提到一点此处用看VC,石油定缺点的,就是效率比正常代码要低一点,但是我也认为这应该是可以接受的。

    备注参考

    http://www.jianshu.com/p/51d33d8f63e9

    相关文章

      网友评论

        本文标题:runtime 自动归档

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