IOS高级教程2:反射根据变量的引用获取变量名

一、使用介绍

项目有的时候,会遇到一些特殊的处理,想要根据一个实例的引用,获取这个实例在代码中的名称。比如在处理View的坐标的时候,我们将UIView的坐标信息配置到plist文件中,我们可以设置一个key,再通过这个key来获取配置文件中的坐标等信息。有没有更简单的方法呢,或者我只想简单的用实例变量的变量名做为key。下面就介绍一种简单的,根据实例变量的引用获取实例变量名的办法。

转载请保留原本链接:http://my.oschina.net/taptale/blog/110626

二、引用文件

第一步,我们需要引入我们需要的头文件,在需要使用的类中引用下面代码

?


1

#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)根据上面的原理我们可以得到第一版本的代码,如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

- (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的时候,需要跳过执行。最终代码如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

- (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;

}

 

时间: 2024-10-28 11:39:35

IOS高级教程2:反射根据变量的引用获取变量名的相关文章

iOS高级教程:处理1000张图片的内存优化

一.项目需求 在实际项目中,用户在上传图片时,有时会一次性上传大量的图片.在上传图片前,我们要进行一系列操作,比如:旋转图片为正确方向,压缩图片等,这些操作需要将图片加载到内存中,下面对内存的使用做详细分析. 二.内存分析,非优化 我在测试项目中,重复加载了一张图片1000次,首先加载图片到内存,然后进行压缩操作,释放内存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 for (int i = 0; i <= 1000; i ++) {     

ios cocopods 安装使用及高级教程

CocoaPods简介 每种语言发展到一个阶段,就会出现相应的依赖管理工具,例如Java语言的Maven,nodejs的npm.随着iOS开发者的增多,业界也出现了为iOS程序提供依赖管理的工具,它的名字叫做:CocoaPods.http://cocoapods.org/ 一.安装 1.更新gem 如果终端gem版本太老可能会有问题,先更新gem:(现在大部分新机都不会有这个问题) sudo gem update --system 2.换源 gem默认的源是外国的https://rubygems

(转发)IOS高级开发~Runtime(二)

一些公用类: @interface ClassCustomClass :NSObject{ NSString *varTest1; NSString *varTest2; NSString *varTest3; } @property (nonatomic,assign)NSString *varTest1; @property (nonatomic,assign)NSString *varTest2; @property (nonatomic,assign)NSString *varTest3

Unity3D for iOS初级教程:Part 3/3(下)

转自:http://www.cnblogs.com/alongu3d/archive/2013/06/01/3111739.html 消息不会自动消除 你基本的游戏功能已经完成了,但是显示一些关于游戏的信息当它首次加载的时候是一个好的亮点.你现在所有显示的是一个play按钮.用户不知道他们要做啥. 添加一些欢迎的文字和关于游戏的超级简短的介绍会让它更加用户友好.:]欢迎的文字会使用你导入变形金刚字体.对于介绍文字.你会使用和Unity一起打包的Arial字体. 创建一个空的游戏对象,命名它为In

Unity3D for iOS初级教程:Part 2/3

转自:http://www.cnblogs.com/alongu3d/archive/2013/06/01/3111736.html 这篇教材是来自教程团队成员 Christine Abernathy, 他是Facebook的开发支持团队的工程师.欢迎来到Unity3D for iOS系列教程的第二部分!在这个系列的第一部分中,你已经学习了Unity的一些基本技能来构建一个非常简单的项目,并把它部署到iOS设备上.在继续这篇教程之前,你要确认已阅读过第一部分.现在进入第二部分,你要添加一些功能来

DOS批处理高级教程

转载-->http://blog.csdn.net/lanbing510/article/details/7461073 前言 本教程主要引用伤脑筋版主的系列文章,同时参考引用[英雄]教程等其他批处理教程,本文将这些文章合并在一起,并尽量修改得详细而且简单易懂,修改整理也是学习过程,主要目的是方便自己以后查阅.    本教程很长啊,需要一定的耐心才能看完,能够看完的话,差不多就是批处理高手了,即使不是高手也是熟手了.本教程还在不断补充之中,当有比较典型的应用技巧时,本教材会将其收入相关的章节之中

MPLS VPN 高级教程(张洋讲解演示版)

MPLS VPN 高级教程(张洋讲解演示版) 课程目标: ü        LDP的实施和特性 ü        PE-CE路由协议以的实施,以及它们在MPLS VPN中的特性: ü        如何通过MPLS网络运载IPv6,6PE和6VPE的含义和它的运作过程: ü        MPLS VPN的各种配置方案 适合人群:希望深入理解MPLS-VPN的人群. 课程位置: http://edu.51cto.com/course/course_id-5737.html 具体内容:   第一课

IOS block 教程&lt;转&gt;

http://pernghh.pixnet.net/blog/trackback/eac87d412e/33563409 本文来自台湾的某开发人员的博客,被墙,感觉讲的比较易懂,所以引过来.文字简体化了,原来是繁体,变数=变量,这个注意一下. 本章学习目标: 1. 了解何谓block. 2. 了解block的使用方法. Block 是iOS在4.0之后新增的程式语法,严格来说block的概念并不算是基础程式设计的范围,对初学者来说也不是很容易了解,但是在iOS SDK 4.0之后,block几乎

Swift研究之编程高级教程(二)属性,存储属性详解

 属性 属性是依赖于某个特定的类.结构体或者枚举类型的值.Swift有两种属性:存储类型和计算类型.其中存储类型可以作为实例的一部分存放变量或者常量的值,而计算类型的属性值是通过运算的来的.计算类型的属性可以在类.结构体和枚举类型中出现,但存储类型只可能出现在类和结构体类型中. 属性一般依赖于一个特定类型的实例,但是也可以依赖于类本身.依赖于类型本身的属性称为类型属性. 可以定义属性观察者来监督属性值的改变,从而作出响应.对集合不明白的看集合类型-数组详解 存储属性 常量属性let的值在初始