【iOS】利用runtime获取某个类的属性

作者: Always_on | 来源:发表于2017-01-14 14:57 被阅读300次

    runtime对于大家并不陌生,开发中用到runtime的地方并不少,很多情况下runtime实现了OC无法实现的东西;
    我们写的OC代码,在程序运行时都转变了runtime的C代码,runtime属于OC的底层实现,就OC层面而言,OC无法实现的可以利用runtime实现,而且很方便;
    那么runtime有什么用呢

    1.程序运行中动态创建一个类;
    2.动态为某个类添加修改方法和属性
    3.可以遍历一个类的所有成员变量和方法;
    

    首先我们来看一下runtime如何将OC代码转为C
    新建工程,并创建一个继承NSObject的CYObject类

    CYObject *obj = [[CYObject alloc]init];
    

    接下来在终端下使用clang将其编译

    Snip20170114_8.png

    C代码如下

    CYObject *obj = ((CYObject *(*)(id, SEL))(void *)objc_msgSend)((id)((CYObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("CYObject"), sel_registerName("alloc")), sel_registerName("init"));
    

    通过对比我们可以发现
    alloc:objc_msgSend 给objc_getClass("CYObject")发送sel_registerName("alloc")
    init:objc_msgSend 给obj发送sel_registerName("init")
    其方法调用实际就是消息发送机制;
    那么runtime如何使用,以获取某个类的属性为例;
    使用runtime需要我们导入头文件

    #import <objc/runtime.h>
    #import <objc/message.h>
    

    我们点进去runtime.h可以看到如下定义

    /// An opaque type that represents a method in a class definition.
    //成员方法
    typedef struct objc_method *Method;
    
    /// An opaque type that represents an instance variable.
    //成员属性
    typedef struct objc_ivar *Ivar;
    
    /// An opaque type that represents a category.
    //类别Category
    typedef struct objc_category *Category;
    
    /// An opaque type that represents an Objective-C declared property.
    //类中声明的属性
    typedef struct objc_property *objc_property_t;
    

    比较重要的函数

    //拷贝出一个对象的所有成员变量列表
    Ivar *class_copyIvarList(Class cls, unsigned int *outCount);
    //拷贝出一个对象的所有成员方法列表
    Method *class_copyMethodList(Class cls, unsigned int *outCount) ;
    

    message.h中两个重要函数

    //给某个对象发送消息
    objc_msgSend
    //给摸某个对象的父类发送消息
    objc_msgSendSuper
    

    接下来创建工程,创建CYObject类
    CYObject.h

    #import <Foundation/Foundation.h>
    
    @interface CYObject : NSObject
    @property (nonatomic ,copy) NSString *name;
    @property (nonatomic ,copy) NSString *address;
    @end
    

    CYObject.m

    #import "CYObject.h"
    @interface CYObject()
    @property (nonatomic ,assign) int age;
    @property (nonatomic ,assign) int height;
    @end
    @implementation CYObject
    @end
    

    CYObject.m中age和height为私有,目的是利用runtime获取.m中的属性
    获取属性代码如下

    unsigned int count = 0;
        
        Ivar *ivars = class_copyIvarList(NSClassFromString(@"CYObject"), &count);
        //ivars不是数组而是内存地址
        
        NSLog(@"count:%d",count);
        
        for (int i = 0; i < count; i++) {
            //获取成员变量
            Ivar ivar = ivars[i];
            
            const char *name = ivar_getName(ivar);
            
            NSString *sname = [NSString stringWithUTF8String:name];
            
            NSLog(@"sname:%@",sname);
        }
        free(ivars);
    

    打印结果:

    2017-01-14 14:55:23.286 runtime2[2037:82444] count:4
    2017-01-14 14:55:23.286 runtime2[2037:82444] sname:_age
    2017-01-14 14:55:23.287 runtime2[2037:82444] sname:_height
    2017-01-14 14:55:23.287 runtime2[2037:82444] sname:_name
    2017-01-14 14:55:23.287 runtime2[2037:82444] sname:_address
    

    从打印结果中可以看出,即使是.m文件中的私有属性,利用runtime依然可以获取。

    相关文章

      网友评论

        本文标题:【iOS】利用runtime获取某个类的属性

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