iOS rumtime 笔记五 — 遍历类的属性,进行归档

这两天把Runtime的知识重新理了一遍,把之前做的数据持久化(将一个model序列化后存放到userdefault中)又封装了一遍。
下面是介绍

需求

我们在开发中,经常需要对一些信息进行归档化保存。举个例子,我们用作登陆的页面,登陆后需要获取到一个tokensession ID. 这个token在之后所有的request都是要调用到的。除此之外,request可能还需要其他的一些信息,比如用户的用户名,请求类型,都需要保存。

个人之前的做法,就是将请求返回的JSON转化为model之后,序列化存成二进制,放入userDefault中。
但是通常model具有的property会相当多,如果都去实现NSCoding的代理,势必非常繁琐。

采用runtime遍历属性的方式,在 decoderencoder中去实现方法。

代码及描述

创建两个类:

  • BaseArchiveModel —— 所有待序列化model类的基类,在该类中实现NSCodingdelegate
    暴露出两个接口,供他的子类存取时调用。
    /**将类的实例保存至沙盒*/
    -(void)saveToSandbox;
    /**
    从沙盒中取出类的实例,转化后返回
    @return 实例
    */
    +(instancetype)fetchFromSandbox;
    
  • ArchiverTool —— 一个工具类,用runtime封装遍历属性的方法,在BaseArchiveModel中的delegate去实现他。

下面是代码.

#import "BaseArchiveModel.h"
#import <objc/message.h>

@implementation BaseArchiveModel
-(void)encodeWithCoder:(NSCoder *)aCoder {
    [ArchiverTool encodeWithClassName:[self class] modelInstance:self aCoder:aCoder];
}

-(id)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        [ArchiverTool decodeWithClassName:[self class] modelInstance:self aCoder:aDecoder];
    }
    return self;
}

-(void)saveToSandbox {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    NSLog(@"存入沙盒的属性名 = %@",NSStringFromClass([self class]));
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:NSStringFromClass([self class])];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

+(instancetype)fetchFromSandbox {
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
    NSData *tempData = [user objectForKey:NSStringFromClass([self class])];
    NSLog(@"沙盒中取出的属性名 = %@",NSStringFromClass([self class]));
    id final = [NSKeyedUnarchiver unarchiveObjectWithData:tempData];
    return final;
}
@end


// -------------------------------
@implementation ArchiverTool
+(void)encodeWithClassName:(Class)classname modelInstance:(id)instance aCoder:(NSCoder*)aCoder {
    unsigned int count = 0;
    Ivar *var = class_copyIvarList(classname, &count);
    for (int i = 0; i <count; i++) {
        Ivar property = var[i];
        const char* char_f =ivar_getName(property);
        NSString *propertyName = [NSString stringWithUTF8String:char_f];
        id propertyValue       = [instance valueForKey:(NSString *)propertyName];
        NSLog(@"属性 %@,值 %@",propertyName,propertyValue);
        [aCoder encodeObject:propertyValue forKey:propertyName];
    }
}

+(void)decodeWithClassName:(Class)classname modelInstance:(id)instance aCoder:(NSCoder*)aCoder {
    unsigned int count = 0;
    Ivar *var = class_copyIvarList(classname, &count);
    for (int i = 0; i <count; i++) {
        Ivar property = var[i];
        const char* char_f =ivar_getName(property);
        NSString *propertyName = [NSString stringWithUTF8String:char_f];
        [instance setValue:[aCoder decodeObjectForKey:propertyName] forKey:propertyName];
    }
}

@end

另一种遍历的方法代码(大同小异)

+(void)getKeyAndValueFromModel:(id)myModel {
    NSMutableDictionary *props = [NSMutableDictionary dictionary];
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([myModel class], &outCount);
    for (i = 0; i<outCount; i++){
        objc_property_t property = properties[i];
        const char* char_f =property_getName(property);
        NSString *propertyName = [NSString stringWithUTF8String:char_f];
        id propertyValue       = [myModel valueForKey:(NSString *)propertyName];

        NSLog(@"props>>>>>>>>>>>>>>>>>>>%@",props);
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,216评论 30 472
  • 面试题参考1 : 面试题[http://www.cocoachina.com/ios/20150803/12872...
    江河_ios阅读 1,758评论 0 4
  • iOS网络架构讨论梳理整理中。。。 其实如果没有APIManager这一层是没法使用delegate的,毕竟多个单...
    yhtang阅读 5,257评论 1 23
  • 1.1 谈一谈GCD和NSOperation的区别? 首先二者都是多线程相关的概念,当然在使用中也是根据不同情境进...
    John_LS阅读 1,341评论 0 12
  • VIVIZSH阅读 394评论 0 0