我是靠谱客的博主 多情蜜粉,最近开发中收集的这篇文章主要介绍Objective-C反射机制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

      Objective-C也提供了类似于java的反射机制,这种动态编程机制可以让Objective-C语言更加灵活。Objective-C提供了3种编程方式与运行环境交互。

  •      直接通过Objective-C的源代码。这是最常见的方式,开发人员只是编写Objective-C源代码,而运行环境负责在后台工作。当编译Objective-C源代码时,编译器会创建大量数据结构和动态机制的函数。其中数据结构负责保护类、类别(category)中定义的数据,而函数则负责处理方法调用。
  • 通过NSObject类中定义的方法进行动态编程。因为绝大部分类都是NSObject的子类(NSProxy例外),所以绝大多部分对象都继承了NSobject的方法,故所有的对象都可以直接调用NSObject的方法来编程,在少数情况下,NSObject类只提供了方法模板,并没有为方法实现提供代码。例如,NSObject实现了description方法,该方法返回对象的类名+地址组成的字符串,通过该字符串拉来描述对象,而NSObject的子类则可重写该方法返回更多的详细信息。除此之外,NSObject还提供了isKindOfClass:isMemberOfClass:方法,这两个方法可用于判断该对象所属的类;respondsToSelector:用于判断该实例是否可调用指定方法;conformsToProtocal:用于判断该对象是否遵守指定协议;methodForSelector:则用于返回指定方法的指针。
  •  直接调用运行时函数进行动态编程。运行时系统十一个动态共享库,由一系列位于/usr/include/objc目录的头文件中的函数和数据结构组成,这些工具都是C风格的,它们并不是Objective-C编程必需的,但有些函数在Objective-C编程是也是有用的。如果需要理解这些运行时函数的功能和用法,可参考Xcode帮助系统的Objective-C Runtime Reference帮助手册。

一、获得Class

    每个类都有一个对应的Class,在Objective-C程序中获得Class通常有如下3种方式。

  • 使用Class NSClassFromStringNSString *aClassName)函数来获取Class,该函数需要传入字符串参数,该字符串参数的值是某个类的类名。

  • 调用某个类的class方法来获取该类对应的Class。例如,[Person class]将会返回Person类对应的Class

  • 调用某个对象的class方法,该方法是NSObject类中的实例方法,所以所有的Objective-C对象都可以调用该方法,该方法将会返回该对象所属类对应的Class

    对于定义中方式和第二种方式,都是直接根据类来取得该类的Class对象的,但相比之下,第二种方式有如下两种优势:

    1.代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。

    2.程序性能更好,因为这种方法无需调用方法。

    如果有可能,则应该使用第二种方式来获取指定类的Class。但在实际编程过程中,有时候只能拿到一个字符串,如@”Person”,如果需要获取该字符串对应的Class。则只能使用第一种方式。

    一旦获得了某个类所对应的Class对象之后,测很难过心虚就可以调用Class对象的方法来获得该对象和该类的真实信息了。

例如,如下程序来测试获取Class

ClassTest.m
int main(int argc, char * argv[]){
	
	@autoreleasepool{
		//通过字符串获取Class
		Class clazz = NSClassFromString(@”NSDate”);
NSLog(@”%@”,clazz);
		//直接使用class来创建对象
		id date = [[clazz alloc] init];
NSLog(@”%@”,date);
		//通过对象来获取Class
NSLog(@”%@”,[date class]);
		//通过类来获取Class
NSLog(@”%d”,clazzz == NSDate.class);
	}
	
}

    上面程序测试通过3种方是来获取Class。变异、运行该程序,可以看到如下输出:

NSDate
2015-07-25 13:49:52 +0000
__NSDate
1

    从上面的与运行结果可以看出,通过类名字符串、类本身获取的Class对象是相等的,但通过NSDate对喜爱那个获取的Class则是__NSDate,这是什么原因呢?Objective-C的很多设计都采用类簇的设计,NSDate只是这个类簇的前端,当程序调用[[NSDate alloc] init];创建对象时,程序实际返回的只是NSDate的子类(__NSDate)的实例,而不是NSDate的实例。因此,程序直接调用date对象的class方法来获取Class时返回__NSDate

    从上面的程序可以看出,一旦获得某个类对应的Class之后,程序可以直接调用该Classalloc方法来创建对象,接下来调用init方法执行初始化即可。从程序的与西宁结果可以看到,调用Classalloc方法创建的并不是Class的实例,而是该Class对应的类的。

二、检查继承关系

      如果程序只是需要确认一个类的继承关系,比如,判断它是否为某个类的实例或是否为某个类及其子类的实例,则可以直接带哦用NSObject提供的如下方法来进行判断。

  • isKindOfClass:该方法需要传入一个Class参数,用于判断该对象是否为该类及其子类的实例。

  •  isMemberOfClass:该方法需要传入一个Class参数,用于判断该对象是否为该类的实例。

  • conformsToProtocal:该方法需要传入一个Protocal参数,用于判断该对象是否实现了该协议。

      在上面的3个方法中,第三个方法需要传入一个Protocal参数,为了在程序中获取Protocal对象,可通过如下两种方式来完成。使用Objective-C提供的@protocal指令来实现。可调用Protocal *NSProtocalFromString(NSString *namestr);函数根据协议名字符串来获取对应的协议。

三、动态调用方法


      如果程序需要动态调用对象的settergetter方法,则可通过Objective-C提供的KVC机制来实现;如果程序需要访问对象的实例变量的值,那么不管这个实例变量是否存在类的接口部分定义,也不管该变量使用哪种访问控制符修饰,或者是否在类的实现部分定义,程序都可以通过KVC机制来设置、访问实例变量的值。

      如果程序需要判断某个对象是否可以调用方法,则可通过NSObject的如下方法来进行判断。

      respondsToSelector::该方法需要传入一个SEL参数--Objective-C把方法称为选择器,因此,Objective-C使用SEL对象来代表方法。如果该对象可调用该方法,那么该方法返回YES:否则发返回NO

      在上面的方法中传入一个方法作为参数,即需要传入SEL对象作为参数。为了在程序中动态获取SEL对象,Objective-C提供了如下方法。

  •  使用@selector指令来获取当前类中指定的方法。该指令需要传入完整的的方法签名关键字作为参数,仅有方法名是不够的。
  • 使用SEL NSSelectorFromString(NSString *aSelectorName)函数根据方法签名关键字的字符串获取对应的方法。

      如果程序需要动态调用对象的普通方法,则可通过如下两种方式来实现。

  •  通过NSObject提供的系列performSelector:方法来实现,该方法的第一个西安书需要传入一个SEL对象。如果调用方法需要传入参数,则还可以通过withObject:标签来传入参数。
  • 使用objc_msgSend(receiver,selector,...)函数来调用。该函数的第一个参数是方法调用者,第二个参数代表调用的方法,接下来的参数将作为调用方法的参数。



注:参考自《疯狂IOS讲义(上)》

 



最后

以上就是多情蜜粉为你收集整理的Objective-C反射机制的全部内容,希望文章能够帮你解决Objective-C反射机制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部