runtime之归档反归档

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>


// 归档的前提:被归档的对象需要遵守编码协议,并实现相应方法

@interface User : NSObject <NSCoding>


@property (nonatomic,assign) NSInteger age; // 年龄integer类型


@property (nonatomic,copy) NSString *name; // 姓名,oc类型


@property (nonatomic,strong) UIImage *image; // 图片,UIImage类型


@end


#import "User.h"

#import <objc/runtime.h> // 导入运行时头文件


 // 注意,不把存储我们 属性名 属性类型字典 进行归档

// 因为归档是一个重新创建的过程,因为我们把 存储 属性名  属性类型的字典设置为全局的

static NSMutableDictionary *proDic = nil;


@interface User () <NSCacheDelegate>


@end



@implementation User


// 归档是一个编码的过程

- (void)encodeWithCoder:(NSCoder *)aCoder

{

    


    

   proDic = [NSMutableDictionary dictionary];

    

    // 获取类中的实例变量

    unsigned int count; // 属性个数

    

    // 定义Ivar, 获取所有的实例变量

    Ivar *varArray = class_copyIvarList([self class], &count);

    

    // 循环归档的过程

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

        

        Ivar var = varArray[i];

        

        // 1. 获取属性名称 : age      name       image

        const char *cName = ivar_getName(var); // 获取属性名,c字符串

        NSString *proName = [[NSString stringWithUTF8String:cName] substringFromIndex:1]; // OC字符串

        

        // 注意需要截取一下

        

        

        // 2. 获取属性类型 : NSInteger NSString  UIImage

        const char *cType = ivar_getTypeEncoding(var); // 获取 变量类型。

        

        

        // 3. kvc 取值

        id value = [self valueForKey:proName];


        

        // 4. 把属性类型  C 字符串 转化为 OC 字符串,会加上 @"  "

        // 属性类型

        NSString *proType = [NSString stringWithUTF8String:cType];

        

        // 5. 如果是OC类型数据,且不属于 NSNumber类,把 @"  " 去掉

        if ([value isKindOfClass:[NSObject class]] && ![value isKindOfClass:[NSNumber class]]) {

            

            // 截取前: @"@\"NSString\""

            // 截取后: @\"NSString\"

            NSUInteger length = proType.length;

            proType = [proType substringWithRange:NSMakeRange(2, length - 3)];

            

        }

        

        

        // 6. 存储属性   属性类型的 字典赋值 属性名(key___ 属性类型(value

        if (![proName isEqualToString:@"proDic"]) {

            

            [proDic setValue:proType forKey:proName];

        }

        

        

        

        // 注意: 这里c语言基本数据类型,可以写一个数组,然后判断是否在数组

        // 注意,不把存储我们 属性名 属性类型字典 进行归档

        if ([proType isEqualToString:@"q"]) { // 如果属性类型为q, 说明为NSInteger类型为age

            

            // 说明是 NSInteger类型,使用KVC取值,取出的是 NSNumber类型,需要转化为integer类型

            [aCoder encodeInteger:[value integerValue] forKey:proName];

            

        } else if ([proType isEqualToString:@"UIImage"]) // image

        {

            // 说明是图片,需要转化为data再存储

            [aCoder encodeDataObject:UIImagePNGRepresentation(value)];

            

        }else if ([value isKindOfClass:[NSObject class]] && ![proName isEqualToString:@"proDic"]) // string

        {

            // 如果 value oc对象,使用Object归档

            [aCoder encodeObject:value forKey:proName];

        }

        

    } // for 循环归档结束

    

    

    

}




// 反归档是一个解码的过程,初始化方法重新生成对象

- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder

{

    

    self = [super init];

    

    if (self) {

        

        // 1. 遍历变量名, 变量名为 归档、返归档 标识

        for (NSString *name in proDic) {

            

            

            // 2. 获取变量类型,根据类型反归档

            NSString *type = proDic[name];

            

            // 循环反归档过程

            // kvc 赋值

            if ([type isEqualToString:@"q"]) { // age

                

                NSInteger integer  = [aDecoder decodeIntegerForKey:name]; // 注意需要把 NSNumber  ----> NSInteger 类型

                

                // 优化部分:需要赋值的对象 这里需要用到 setObjectForKey NSCache 以后解决

                

                Ivar var = class_getClassVariable([self class], name.UTF8String);

//                obje

                

                self.age = integer;

                

                

            } else if ([type isEqualToString:@"UIImage"]) {

                

                UIImage *image = [UIImage imageWithData:[aDecoder decodeDataObject]];

                [self setValue:image forKey:name];

                

            } else

            {

                id value = [aDecoder decodeObjectForKey:name];

                [self setValue:value forKey:name];

            }

            

        }

        

    }

    return self;

}





#pragma mark-

#pragma mark NSCache 协议方法

//- (void)cache:(NSCache *)cache willEvictObject:(id)obj

//{

//    

//}













@end



#import "ViewController.h"


#import <objc/runtime.h>


#import "User.h"


#define varString(var) [NSString stringWithFormat:@"%s",#var]


@interface ViewController ()


@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    

    // objec/runtime

    // OC 动态运行时 归档反归档

    

    unsigned int count;

    // 获取类的 实例变量

    Ivar *array = class_copyIvarList([Person class], &count);

    

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

        

        // 获取 实例变量的类型

        NSLog(@"%s", ivar_getTypeEncoding(array[i]));


    }

    

    /*

     2015-11-22 14:27:32.647 runtime之归档反归档[59048:1932097] q

     2015-11-22 14:27:32.647 runtime之归档反归档[59048:1932097] @"NSString"

     2015-11-22 14:27:32.648 runtime之归档反归档[59048:1932097] @"UIImage"

     

     typedef long NSInteger  ivar_getTypeEncoding  q

     */

    

    User *user = [[User alloc] init];

    user.age = 12;

//    [person setValue:@12 forKey:@"age"];

    NSInteger age = [[user valueForKey:@"age"] integerValue];

    // kvc 赋值,虽然可以会把 基本数据类型 ,转化为 NSNumber 添加进去,

    // 但是取值的时候一定要注意,也需要把  NSNumber 转化为 interger,否则打印的integer 值不正确

    

    NSLog(@"%ld", age);

    

    NSLog(@"%@", [person valueForKey:@"age"]);

    

    

    User *p1 = [[Person alloc] init];

    p1.age = 16;

    p1.name = @"XL";

    p1.image = [UIImage imageNamed:@"avatar.jpg"];

    

    

    

    

    // 归档

    NSMutableData *data1 = [NSMutableData data];

    

    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data1];

    

    NSString *varName =  varString(p1);

    

    [archiver encodeObject:p1 forKey:varName];

    

    [archiver finishEncoding];

    

//    NSLog(@"%@", data1);

    NSLog(@"%@", varName);

    

    

    // 反归档

    NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data1];

    

    User *p2 = [unArchiver decodeObjectForKey:varName];

    

    [unArchiver finishDecoding];

    

    NSLog(@"%@", p2);

    

    

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRectMake(100, 100, 200, 200))];

    imageView.image = p2.image;

    [self.view addSubview:imageView];

    

    NSLog(@"%ld", p2.age);

    NSLog(@"%@", p2.name);

    // Do any additional setup after loading the view, typically from a nib.

}


@end



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值