反射根据变量的引用获取变量名
2014-11-12 11:33
246 查看
一、使用介绍
项目有的时候,会遇到一些特殊的处理,想要根据一个实例的引用,获取这个实例在代码中的名称。比如在处理View的坐标的时候,我们将UIView的坐标信息配置到plist文件中,我们可以设置一个key,再通过这个key来获取配置文件中的坐标等信息。有没有更简单的方法呢,或者我只想简单的用实例变量的变量名做为key。下面就介绍一种简单的,根据实例变量的引用获取实例变量名的办法。转载请保留原本链接:http://my.oschina.net/taptale/blog/110626
二、引用文件
第一步,我们需要引入我们需要的头文件,在需要使用的类中引用下面代码#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)根据上面的原理我们可以得到第一版本的代码,如下:- (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的时候,需要跳过执行。最终代码如下:
- (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; }
相关文章推荐
- 反射根据变量的引用获取变量名
- IOS高级教程2:反射根据变量的引用获取变量名
- IOS高级教程2:反射根据变量的引用获取变量名
- IOS高级教程2:反射根据变量的引用获取变量名
- 根据变量的引用,获取变量名
- [反射初探]根据反射获取类中参数类型及参数名和参数值
- C#泛型、反射-根据对象名获取该类型以及其属性
- 根据作用域来确定恰当的变量引用
- java 中通过反射获取私有变量的值
- 使用反射创建Bean、Spring中是如何根据类名配置创建Bean实例、Java提供了Class类获取类别的字段和方法,包括构造方法
- 使用反射创建Bean、Spring中是如何根据类名配置创建Bean实例、Java提供了Class类获取类别的字段和方法,包括构造方法
- Android(java)学习笔记109:通过反射获取成员变量和成员方法并且使用
- 根据C++标准,如果const的引用被初始化为对一个临时变量的引用,那么它会使这个临时变量的生命期变得和它自己一样
- Java笔记——利用反射机制获取成员变量及成员方法
- java 反射 - 获取成员变量的值.
- 通过反射根据类名获取到类的实例
- 根据变量值获取变量名
- C#中根据变量获取变量名字符串
- C# 中反射获取某类的子类和根据类型名动态创建对象(转载)
- java中通过反射强力获取私有变量的值