运行时是苹果提供的比较底层的C语言API(C语言库) 利用运行时可以:
可以获得对象中的所有成员变量,成员属性,成员方法 以及其它很牛逼的功能。这里暂且只介绍上一点。
需求背景
需求:更改UITextField里占位文字的颜色,而我们不知道怎么改,猜测它有个label用来显示占位文字,但头文件里没有暴露,我们要怎么证明它有这个成员变量并且拿到它呢?
具体使用
导入头文件<objc/runtime.h>
用到下面这个方法:Ivar的意思是instance varlables(成员变量)。给它一个类,他会把这个类里面的所有成员变量返回给你。其中第一个参数是要传一个类,第二个参数要传个unsigned int类型的数据,用来告诉你有多少个成员变量。注意它有个星号*
,要传指针指向的内存地址,要加个&。传入指针指向的地址,它才能改掉地址里的内容。
class_copyIvarList(<#__unsafe_unretained Class cls #> , <#unsigned int *outCount #> )
unsigned int count = 0 ;
Ivar *ivars = class_copyIvarList([UITextField class ], &count );
Ivar上面说过了,就是成员变量。UITextField这个类里面有多个成员变量,是个数组,指针会指向数组中的第一个元素(C语言知识) 然后取出这个元素:*ivars
就是指针指向的地址的内容,注意区别于上面Ivar *ivars
是定义了一个指针,实际意思是(Ivar *)ivars
(又是C语言的知识)。通过ivar_getName(Ivar v)方法可以拿到名称,打印。
Ivar firstIvar = *ivars ;
NSLog(@" %s ",ivar_getName(firstIvar));
然后查看第二个元素:指针指向数组,只要让指针+1就可以看第二个元素了
Ivar secondIvar = *(ivars + 1 );
NSLog (@"%s" ,ivar_getName(secondIvar));
for (int i = 0 ; i < count ; i++) {
Ivar ivar = *(ivars + i);
NSLog(@"%s" ,ivar_getName(ivar));
}
最后,这个类不归ARC管理,上面有copy了记得释放free(ivars);
回到需求背景
用运行时可以看到UITextfield里确实有个_placeholderLabel成员变量,而且是在.m文件里定义的(带下划线的),没有直接暴露在外面给我们拿到。 直接没法拿到,那么可以通过KVC来拿到
UILabel *placeholderLabel = [self valueForKeyPath:@"_placeholderLabel" ];
然后对着placeholderLabel想怎么设置就怎么设置
placeholderLabel.textColor = [UIColor redColor];
[self set Value:[UIColor redColor] for KeyPath:@"placeholderLabel.textColor" ];
其它运行时的方法
unsigned int count = 0 ;
objc_property_t *propertys = class_copyPropertyList([UITextField class ], &count );
for (int i = 0 ; i < count ; i++) {
objc_property_t property = propertys[i];
NSLog(@"%s" ,property_getName(property ));
}
free(propertys);
小知识点:用@property生成的成员属性和会自动生成一个带下划线的成员变量,所以有成员属性一定有成员变量,而有成员变量不一定有成员属性,因为可以自己定义下划线的成员变量而不是通过定义成员属性来定义。 还有找出类里面的方法
Method *methods = class_copyMethodList (<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)