iOS runtime详解

runtime(运行时机制)

简介
1.Runtime是一套底层的纯C语言的API,属于C语言的一个库,里面包含了很多底层的C语言的API
2.平时编写的OC代码,在程序运行过程中,其实最终都转成了runtime的C语言的代码,runtime算是OC的幕后工作者
3.比如这段OC代码:
        XPerson *obj = [[XPerson alloc] init];
        obj.name = @"syj";
    runtime C 代码:
        XPerson *obj = objc_msgSend(objc_msgSend(objc_getClass("XPerson),@selector(alloc)),@selector(init));
        objc_msgSend(obj,@selector(setName:),@"syj");
runtime的作用
1.在程序运行中动态创建一个类(比如KVC、KVO的底层实现)
2.在程序运行中动态为某个类添加属性和方法,修改属性的值和方法
3.遍历一个类的所有属性和方法(字典转模型,归档时用循环实现)
runtime相关应用
1.NSCoding(归档和解档)
2.字典转模型(json解析封装的那个函数)
3.KVO(利用runtime动态生成一个类)
4.可以用于开发框架(方便更改)
runtime相关的头文件
#import <objc/runtime.h> 包含对类、成员变量、属性、方法的操作
#import <objc/message.h> 包含消息机制
runtime常用方法
objc_msgsend:给对象发送消息
class_copyMethodList:遍历某个类所有的方法
class_copyIvarList:遍历某个类所有的成员变量
runtime官方文档(部分摘选)
Method
Method 代表类中某个方法的类型

typedef struct objc_method *Method;

struct objc_method {
    SEL method_name        //方法名类型为SEL                                  
    char *method_types     //方法类型是个char指针,存储方法的参数类型和返回值类型                                  
    IMP method_imp         //method_imp指向了方法的实现,本质是一个函数指针                                 
}

objc_method存储了方法名,方法类型,方法实现                                                            
Ivar
Ivar 是表示成员变量的类型


typedef struct objc_ivar *Ivar;

struct objc_ivar {
    char *ivar_name                                          
    char *ivar_type                                          
    int ivar_offset     //基地址偏移字节                                     
#ifdef __LP64__
    int space                                                
#endif
}
Category
typedef struct objc_category *Category;

struct objc_category {
    char *category_name                                      
    char *class_name                                         
    struct objc_method_list *instance_methods                
    struct objc_method_list *class_methods                   
    struct objc_protocol_list *protocols                     
}
Property
typedef struct objc_property *objc_property_t;
可以通过class_copyPropertyList和protocol_copyPropertyList方法获取类和协议中的属性
Class
Class是指向objc_class结构体的指针

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                       //父类指针                
    const char *name                        //类名               
    long version                                            
    long info                                               
    long instance_size                                      
    struct objc_ivar_list *ivars            //成员变量列表                
    struct objc_method_list **methodLists   //方法列表        
    struct objc_cache *cache                //缓存                
    struct objc_protocol_list *protocols    //协议                
#endif

} 
/* Use `Class` instead of `struct objc_class *` */
字典转模型
+ (NSMutableArray *)customModel:(NSString *)modelClass ToArray:(id)jsonArray
{

//用来存放一个类中有几个成员变量。
unsigned int outCount = 0;

//这句话执行之后outCount的值就会是当前类中属性的个数。整体返回的是一个指针数组,里面包含对应类的各个属性信息。
objc_property_t *properties = class_copyPropertyList(objc_getClass(modelClass), &outCount);

//创建一个数组用来存放对象;
NSMutableArray *objectArr = [[NSMutableArray alloc] initWithCapacity:1];

for (int i = 0; i < [jsonArray count]; i++)
{
    //取出数组中的一个对象
    id jsonDic = [jsonArray objectAtIndex:i];
    
    //若数组中的对象不是字典对象就跳过它。继续下一个。
    if(![jsonDic isKindOfClass:[NSDictionary class]])
    {
        continue;
    }
    
    //创建一个传过来字符串(类名)相应的对象
    id model = [[objc_getClass(modelClass) alloc] init];
    
//        [model setValuesForKeysWithDictionary:jsonDic];
    
    //判断类中的每一个属性
    for (int j = 0; j < outCount; j++)
    {
        //获取类中的第j个成员变量信息
        objc_property_t property = properties[j];
        
        //获取类中的第j个成员变量将其转化为字符串
        NSString *propertyName =[NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        
        //获得json串中的键对应的值
        id value = [jsonDic objectForKey:propertyName];
        
        //判断上面取得的值是否存在,不存在就去转换下一个属性
        if(!value || [value isKindOfClass:[NSNull class]])
        {
            continue;
        }
        
        [model setValue:value forKey:propertyName];
    }
    //把转化完成的对象加到一个数组中。
    [objectArr addObject:model];
    
}

CFRelease(properties);

return objectArr;
}
归档解档

把自己定义的类所创建的对象直接写入文件的步骤:

自定义类遵循NSCoding协议,实现NSCoding协议中的两个方法:
    encodeWithCoder:往文件中写入实例变量
    initWithCoder:从文件中读取实例变量为当前对象赋值
如何把对象写入文件:调用NSKeyedArchiver中的archiverRootObject:toFile:
如何把对象从文件中读取出来:调用NSKeyedUnarchiver中的unarchiveObjectWithFile:

代码如下:

//归档(将数据存入文件)
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    //归档存储自定义对象
    unsigned int count = 0;
    //获得指向该类所有成员变量的指针
    Ivar *ivars = class_copyIvarList([self class], &count);

    for (int i = 0; i < count; ++i)
    {
        Ivar ivar = ivars[i];
        //获得成员变量的名称
        const char *keyName = ivar_getName(ivar);
    
        NSString *key = [NSString stringWithUTF8String:keyName];
        //编码每个属性,利用KVC取出每个属性对应的值
        [aCoder encodeObject:[self valueForKey:key] forKey:key];
    }
    free(ivars);
}


//解档并初始化(读取文件中的数据)
- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init])
    {
        unsigned int count = 0;
        //获取指向该类所有成员变量的指针
        Ivar *ivars = class_copyIvarList([self class], &count);
    
        for (int i = 0; i < count; ++i)
        {
            Ivar ivar = ivars[i];
            //获得成员变量的名称
            const char *keyName = ivar_getName(ivar);
        
            NSString *key = [NSString stringWithUTF8String:keyName];
            //解码每个属性,利用KVC为每个属性赋值
            [self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
        }
    
        free(ivars);
    }
    return self;
}

转载于:https://www.cnblogs.com/s-y-j/p/5994438.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值