Runtime实现iOS对象的归档和解档

作者: wuyukobe | 来源:发表于2018-08-03 17:34 被阅读19次

    对遵循了NSCoding协议的iOS对象进行归档和解档是我们经常用到的一种数据持久化方式。

    • 创建一个People类,并遵循NSCoding协议:
    @interface People : NSObject<NSCoding>
    //需要归档的属性
    @property(nonatomic,copy)NSString * time;
    @property(nonatomic,copy)NSArray * dataArray;
    @end
    
    • People.m中实现NSCoding的协议方法:
    #pragma mark - 实现NSCoding的协议方法
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        //需要归档的属性
        [aCoder encodeObject:self.time forKey:@"time"];
        [aCoder encodeObject:self.dataArray forKey:@"dataArray"];
        NSLog(@"调用了 encodeWithCoder:");
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self = [super init];
        if (self) {
            //解档
            self.time = [aDecoder decodeObjectForKey:@"time"];
            self.dataArray = [aDecoder decodeObjectForKey:@"dataArray"];
            NSLog(@"调用了 initWithCoder:");
        }
        return self;
    }
    

    这样虽然能够实现People的归档和解档,但如果People类有许多个属性,那么我们需要对每个属性都实现一遍encodeObject:forKey:decodeObjectForKey:方法,这样就会显得比较繁琐,但是我们可以利用Runtime获取所有属性来重写归档解档方法。如下:

    • 创建一个NSObject的分类@interface NSObject (Runtime):

    .h中声明两个归档解档的方法:

    @interface NSObject (Runtime)
    - (void)encoder:(NSCoder *)aCoder;
    - (void)decoder:(NSCoder *)aDecoder;
    @end
    

    .m中利用Runtime重写归档解档的方法:

    - (void)encoder:(NSCoder *)aCoder {
        unsigned int count = 0;
        Ivar * ivars = class_copyIvarList([self class], &count);
        for (int i=0; i<count; i++) {
            Ivar ivar = ivars[i];
            NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
            id value = [self valueForKey:key];
            [aCoder encodeObject:value forKey:key];
        }
        //在OC中使用了Copy、Creat、New类型的函数,需要释放指针!(注:ARC管不了C函数)
        free(ivars);
    }
    
    - (void)decoder:(NSCoder *)aDecoder {
        unsigned int count = 0;
        Ivar * ivars = class_copyIvarList([self class], &count);
        for (int i=0; i<count; i++) {
            Ivar ivar = ivars[i];
            NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
            id value = [aDecoder decodeObjectForKey:key];
            [self setValue:value forKey:key];
        }
        free(ivars);
    }
    

    并在NSCoding的协议方法中分别调用这两个方法:

    #pragma mark - 实现NSCoding的协议方法
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        //需要归档的属性
        [self encoder:aCoder];
        NSLog(@"调用了 encodeWithCoder:");
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self = [super init];
        if (self) {
            //解档
            [self decoder:aDecoder];
            NSLog(@"调用了 initWithCoder:");
        }
        return self;
    }
    

    这样在分类中调用的好处是其他遵循了NSCoding协议的对象想要实现归档和解档只需要导入头文件#import "NSObject+Runtime.h”并在NSCoding的协议方法中调用[self encoder:aCoder];[self decoder:aDecoder];即可。

    • ViewController中去调用People的归档和解档方法:
    People * p = [[People alloc]init];
    p.time = @"今天";
    p.dataArray = @[@"encode",@"decode"].copy;
    //归档
    [NSKeyedArchiver archiveRootObject:p toFile:self.filePath];
    //解档
    People * people = [NSKeyedUnarchiver unarchiveObjectWithFile:self.filePath];
    NSLog(@"解档:%@,%@",people.time,people.dataArray);
    

    打印结果为:

    2018-08-03 17:07:51.586114+0800 WXQNSCoding_Runtime[7699:318222] 调用了 encodeWithCoder:
    2018-08-03 17:07:51.587473+0800 WXQNSCoding_Runtime[7699:318222] 调用了 initWithCoder:
    2018-08-03 17:07:51.587695+0800 WXQNSCoding_Runtime[7699:318222] 解档:今天,(
        encode,
        decode
    )
    
    我们也可以把实现NSCoding的协议方法定义为一个宏,这样我们一个宏K_NSCODING_METHOD就搞定了NSCoding的协议方法的实现:
    #define K_NSCODING_METHOD \
    - (void)encodeWithCoder:(NSCoder *)aCoder { \
    [self encoder:aCoder]; \
    NSLog(@"调用了 encodeWithCoder:"); \
    } \
    \
    - (instancetype)initWithCoder:(NSCoder *)aDecoder { \
        self = [super init]; \
        if (self) { \
            [self decoder:aDecoder]; \
            NSLog(@"调用了 initWithCoder:"); \
        } \
        return self; \
    } \
    

    Demo地址:Runtime实现iOS对象的归档和解档

    相关文章

      网友评论

        本文标题:Runtime实现iOS对象的归档和解档

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