内省
内省(Introspection)是面向对象语言和环境的一个强大特性,Objective-C和Cocoa在这个方面尤其的丰富。内省是对象揭示自己作为一个运行时对象的详细信息的一种能力。这些详细信息包括对象在继承树上的位置,对象是否遵循特定的协议,以及是否可以响应特定的消息。NSObject协议和类定义了很多内省方法,用于查询运行时信息,以便根据对象的特征进行识别。
明智地使用内省可以使面向对象的程序更加高效和强壮。它有助于避免错误地进行消息派发、错误地假设对象相等、以及类似的问题。下面的部分将介绍如何在代码中有效地使用NSObject
的内省方法。
本部分包括如下内容:
评估继承关系
一旦您知道一个对象属于什么类,就可能已经相当了解这个对象了。您可以知道它具有什么能力、哪些属性、以及可以响应哪些消息。即使在内省之后不能了解对象所属的类,也可以知道该对象不能响应特定的消息。
NSObject
协议声明了几个方法,用于确定对象在类层次中的位置。这些方法在不同粒度上进行操作,比如class
和superclass实例方法分别返回代表类和超类的Class
对象。使用这些方法需要将一个Class
对象和另一个进行对比。列表2-7给出了一个简单(可能是没有价值)的用法实例。
列表2-7 使用类和超类的方法
// ... |
请注意:有些时候您需要通过class
或superclass
方法得到正确的类消息接收者。
更加常见的是检查对象类的从属关系,这种情况下您需要向该对象发送isKindOfClass:或isMemberOfClass:消息。前一个方法返回接收者是否为给定类或其继承类的实例,isMemberOfClass:
消息则告诉您接收者是否为指定类的实例。isKindOfClass:
方法通常更有用,因为通过它可以知道是否可以向该对象发送一系列消息。考虑列表2-8中的代码片断:
列表2-8 使用isKindOfClass:方法
确定tem对象是NSData
类的继承类的实例之后,代码就知道可以向它发送NSData
的bytes
和length
消息。假定item是NSMutableData类的一个实例,则isKindOfClass:
和isMemberOfClass:
之间的差别就变得更加明显。如果您调用的是isMemberOfClass:
,而不是isKindOfClass:
,条件控制块中的代码将永远不会被执行,因为item并不是NSData
类的实例,而是其子类NSMutableData
的实例。
NSObject还有两个功能更加强大的内省方法,即respondsToSelector:和conformsToProtocol:。这两个方法分别告诉您一个对象是否实现特定的方法,以及是否遵循指定的正式协议(即该对象是否采纳了该协议,且实现了该协议的所有方法)。
在代码中,您可以在类似的情况下使用这些方法。通过这些方法,您可以在将消息或消息集合发送给某些潜在的匿名对象之前,确定它们是否可以正确地进行响应。在发送消息之前进行检查可以避免由不能识别的选择器引起的运行时例外。在实现非正式协议(这种协议是委托技术的基础)时,Application Kit就是在调用委托方法之前检查委托对象是否实现该方法(通过respondsToSelector:
方法)。
列表2-9显示了如何在代码中使用respondsToSelector:
方法。列表2-9 使用respondsToSelector:方法