美文网首页
runtime - 属性与成员变量

runtime - 属性与成员变量

作者: 啊啊啊啊锋 | 来源:发表于2016-07-04 10:34 被阅读42次

利用运行时runtime机制,我们可以获取类文件的属性或者成员变量,还可以为类(当然包括某些分类)动态添加属性或者成员变量,要知道苹果是不允许我们用普通方法为分类增加属性的,但是通过运行时我们就可以做到。

获取类属性或者成员变量:

首先有几个相关的API要弄明白:

/** 获取类所有通过@property方式声明的成员变量或者属性(参数1:要获取成员变量或者属性的类,参数2:unsigned int变量的指针地址,用来存放获取到了多少个成员变量) */
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

/** 获取类所有通过@property以及在@interface大括号里边声明的成员变量或者属性(参数1、2传入参数同上) */   
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

有关这两个方法的区别,请参考这里

首先我们新建一个PropertyTest类,在.h文件中声明几个成员变量和属性

{
    float _webSiteTitle;
    float _privateName;
    float _privateAttribute;
}
@property (nonatomic, assign) int count;
@property (nonatomic, weak) id delegate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) NSArray *names;
@property (nonatomic, strong) NSNumber *atomicProperty;

.m文件中,获取类所有成员变量以及属性

// 获取所有通过@property方式声明的属性
- (void)getAllProperties 
{
    unsigned int count = 0;
    objc_property_t *pros = class_copyPropertyList([self class], &count);
    
    for (unsigned int i=0; i<count; i++) {
    objc_property_t pro = pros[i];
    
    // 'property_getName'获取属性名称
    const char *proName = property_getName(pro);
    
    // 'property_getAttributes'获取属性具体描述
    const char *proAttr = property_getAttributes(pro);
    
    NSLog(@"proName:%s proAttr:%s", proName, proAttr);
    
    unsigned int aCount = 0;
    objc_property_attribute_t *attrs = property_copyAttributeList(pro, &aCount);
        for (int j=0; j<aCount; j++) {
            objc_property_attribute_t attr = attrs[j];
            // 'objc_property_attribute_t'是个结构体,包含'value' 和 'name'两个值
            const char *attrName = attr.name;
            const char *attrValue = attr.value;
            NSLog(@"proName:%s value:%s", attrName, attrValue);
        }
        // 用完之后一定记得手动释放,否则会造成内存泄漏
        free(attrs);
    }
    free(pros);
} 

// 获取所有属性(包括通过在` {} `里边声明的,以及通过@property方式声明的)
- (void)getAllMemberVariables
{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    for (unsigned int i=0; i<count; i++) {
        Ivar ivar = ivars[i];
        const char *name = ivar_getName(ivar);
        const char *type = ivar_getTypeEncoding(ivar);
        NSLog(@"IvarsName:%s encodeType:%s", name, type);
    }
        free(ivars);
}

+ (void)test
{
    PropertyTest *test = [[PropertyTest alloc] init];
    [test getAllProperties];
}

首先我们来看下 getAllProperties 方法打印的结果:

打印结果如下:

让我们来分析下打印结果(第1、2、3和4行是一个属性)(这里我们只分析一个属性的情况,因为其他情况类似):

第一行:
proName(属性名):count  proAttr(属性包含的特性):Ti,N,V_count
第二、三和四行:
分别是对第一行中proAttr的详细解释包括属性名和属性值。

那么第一行中打印的proAttr属性名和属性值分别代表什么呢?我们再来分析,根据苹果官方文档,一个属性的attribute这样组成: T, ... ,V_属性名
其中 *1、T表示属性类型,比如int类型为Ti,id类型为T@,NSString类型为T@"NSString"
    2、中间的...根据不同类型的属性而定义为不同的值,比如'N'表示声明为conatomic,'C'表示属性声明为copy,'&'表示声明为retain... 以此类推
    3、V_属性名 表示实例变量?

更详细的情况可以参考苹果官方文档的解释

我们再看下通过方法 getAllMemberVariables 打印的结果:

由打印结果我们可以看出,这个方法打印出了我们定义的所有属性以及成员变量,其中每一行的
第一个参数:_属性或者成员变量名称  
第二个参数:表示变量类型,比如float类型为'f',int类型为'i',NSString类型为'@NSString'... 以此类推

更详细的情况可以参考苹果官方文档的解释

有了这两个方法,那么我们在动态地获取某个类的变量的时候就方便了很多,相似的,runtime中也有获取类的方法(method)、协议(protocol)等列表的API,有兴趣的朋友可以去学习下

Demo地址

相关文章

网友评论

      本文标题:runtime - 属性与成员变量

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