iOS 之通过反射机制获得变量名
2015-02-09 20:27
351 查看
一、使用介绍
项目有的时候,会遇到一些特殊的处理,想要根据一个实例的引用,获取这个实例在代码中的名称。比如在处理View的坐标的时候,我们将UIView的坐标信息配置到plist文件中,我们可以设置一个key,再通过这个key来获取配置文件中的坐标等信息。有没有更简单的方法呢,或者我只想简单的用实例变量的变量名做为key。下面就介绍一种简单的,根据实例变量的引用获取实例变量名的办法。二、引用文件
第一步,我们需要引入我们需要的头文件,在需要使用的类中引用下面代码[cpp] view
plaincopy
#import <objc/runtime.h>
三、运行原理
我们可以从苹果官方的开发文档中查看到详细的运行时的使用方法及API,官方并没有直接提供根据实例的引用获取实例变量名称的办法,所以我们需要自己去实现。在官方的API中我们可以找到以下几个方法
(1)Describes the instance variables declared by a class.
Ivar * class_copyIvarList(Class cls, unsigned int *outCount)
(2) Reads
the value of an instance variable in an object.
id object_getIvar(id object, Ivar ivar)
(3) Returns
the name of an instance variable.
const char * ivar_getName(Ivar ivar)
根据以上的API,我们可以根据变量的拥有者获取所有变量的Ivar,再迭代所有Ivar,每一次迭代做如下操作
根据(2)中的API,我们可以获取到当前迭代中的Ivar对应的实例变量的引用
将获取到的实例变量与传递过来的实例变量的地址比较
如果地址相同,说明当前的Ivar为传递过来实例变量的Ivar,可以通过(3)获取变量的名称并返回
四、代码
(1)根据上面的原理我们可以得到第一版本的代码,如下:[cpp] view
plaincopy
- (NSString *)nameWithInstance:(id)instance
{
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self.target class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
if ((object_getIvar(self.target, thisIvar) == instance)) {
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
(2)在测试中发现到达上面的if语句的时候,程序有的时候就会crash,经详细测试发现,每次迭代到非objective-c对象的时候,如基本数据类型,BOOL、int、float就会报错。
原因出在object_getIvar这个方法中,当遇到非objective-c对象时,并直接crash,后来查看官方解释
The value of the instance variable specified by ivar, or nil if object is nil.
并没有明确的给出遇到非对象时会crash,也并不会返回nil
我们需要进行一下修正,当遇到非objective-c的时候,需要跳过执行。最终代码如下:
[cpp] view
plaincopy
- (NSString *)nameWithInstance:(id)instance
{
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self.target class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
const char *type = ivar_getTypeEncoding(thisIvar);
NSString *stringType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
if (![stringType hasPrefix:@"@"]) {
continue;
}
if ((object_getIvar(self.target, thisIvar) == instance)) {
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
相关文章推荐
- java中的反射机制,以及如何通过反射获取一个类的构造方法 ,成员变量,方法,详细。。
- 通过反射机制,获得双卡双待机器的IMEI、IMSI、电话号码
- 通过反射机制获得某个类中的属性,构造方法,方法
- JAVA 反射机制 获得 private 变量
- JAVA 反射机制 获得 private 变量
- 反射机制的概述和字节码对象的获取,通过反射获取构造方法并使用;通过反射获取成员变量并使用;通过反射获取私有成员变量并使用;通过反射获取成员方法并使用
- java反射机制 以及通过反射获得类的变量字段,方法,构造函数
- java反射机制 以及通过反射获得类的变量字段,方法,构造函数
- java 的反射机制获得变量及变量值
- Java泛型 通过反射获得方法参数中的变量类名和泛型
- 21天精通java基础之Day19通过反射机制获得类的完整结构
- 通过反射机制,获得双卡双待机器的IMEI、IMSI、电话号码。
- 通过反射机制获得系统字体Size【ActivityManagerNative无法调用问题】
- 通过反射获得类中变量并赋值与调用变量方法
- 通过AIDL及反射机制,使用隐藏API挂断电话
- 通过AIDL及反射机制,使用隐藏API挂断电话
- 使用反射机制 来把一个具体的bean 处理成一个map。并且获得其中的field和值
- iPhone消息推送机制(Push)实现及通过.net应用程序发送消息给ios应用程序
- java 反射机制 读取私有成员变量
- java_通过反射获得泛型的实际类型参数