Objective-C的内省(Introspection)小结

来源:互联网 发布:网络棋牌赌博有鬼吗 编辑:程序博客网 时间:2024/05/13 15:03

在iOS代码中经常用到:isKindOfClass:Class一类的方法,但是对它没有一个了解,在网上搜索了一些内容对它进行了介绍并拓展,这些属于OC的特性之一内省。

内省(Introspection)是面向对象语言和环境的一个强大特性,Objective-C和Cocoa在这个方面尤其的丰富。内省是对象揭示自己作为一个运行时对象的详细信息的一种能力。这些详细信息包括对象在继承树上的位置,对象是否遵循特定的协议,以及是否可以响应特定的消息。NSObject协议和类定义了很多内省方法,用于查询运行时信息,以便根据对象的特征进行识别。


明智地使用内省可以使面向对象的程序更加高效和强壮。它有助于避免错误地进行消息派发、错误地假设对象相等、以及类似的问题。

下面的部分将介绍如何在代码中有效地使用NSObject的内省方法。

 

1、isKindOfClass:Class

检查对象是否是那个类或者其继承类实例化的对象


2、isMemberOfClass:Class

检查对象是否是那个类但不包括继承类而实例化的对象


示例:

Objective-c代码  收藏代码
  1. if ([item isKindOfClass:[NSData class]]) {  
  2.     const unsigned char *bytes = [item bytes];  
  3.     unsigned int length = [item length];  
  4.     // ...  
  5. }  
 

如果item是NSMutableData类实例化的对象,而该类是NSData类的子类,那么[item isKindOfClass:[NSData class]]的值也是TRUE,而[item isMemberOfClass:[NSData class]]的值则为False。
如果item是NSData类实例化的对象,那么[item isMemberOfClass:[NSData class]]的值则为TRUE。



3、respondToSelector:selector

检查对象是否包含这个方法


Objective-c代码  收藏代码
  1. - (void)doCommandBySelector:(SEL)aSelector {  
  2.     if ([self respondsToSelector:aSelector]) {  
  3.         [self performSelector:aSelector withObject:nil];  
  4.     } else {  
  5.         [_client doCommandBySelector:aSelector];  
  6.     }  
  7. }  
 

4、conformsToProtocol:protocol

检查对象是否符合协议,是否实现了协议中所有的必选方法。

Objective-c代码  收藏代码
  1. // ...  
  2. if (!([((id)testObject) conformsToProtocol:@protocol(NSMenuItem)])) {  
  3.     NSLog(@"Custom MenuItem, '%@', not loaded; it must conform to the  
  4.         'NSMenuItem' protocol.\n", [testObject class]);  
  5.     [testObject release];  
  6.     testObject = nil;  


对象的比较

hash和isEqual:方法虽然不是严格的内省方法,但是可以发挥类似的作用,是进行对象的识别和比较时不可或缺的运行时工具。它们并不向运行环境查询对象信息,而是依赖于具体类的比较逻辑。

hash和isEqual:方法都在NSObject协议中声明,且彼此关系紧密。实现hash方法必须返回一个整型数,作为哈希表结构中的表地址。两个对象相等(isEqual:方法的判断结果)意味着它们有相同的哈希值。如果您的对象可能被包含在象NSSet这样的集合中,则需要定义hash方法,并确保该方法在两个对象相等的时候返回相同的哈希值。NSObject类中缺省的isEqual:实现只是简单地检查指针是否相等。

isEqual:的使用相当直接,它将消息的接收者和通过参数传入的对象进行比较。对象的比较常常可以在运行时决定应该对对象做些什么。如列表2-11所示,您可以通过isEqual:来确定是否执行某一个动作。在这个例子中,动作是指保存被修改了的预置信息。

使用isEqual:方法

  1. - (void)saveDefaults {  
  2.  NSDictionary *prefs = [self preferences];  
  3.  if (![origValues isEqual:prefs])  
  4.  [Preferences savePreferencesToDefaults:prefs];  

如果您正在创建子类,则可能需要重载isEqual:方法,以进一步检查对象是否相等。子类可能定义额外的属性,当两个实例被认为相等时,属性的值必须相同。举例来说,假定您创建一个名为MyWidget的NSObject子类,类中包含两个实例变量:name和data。当MyWidget的两个实例被认为是相等时,这些变量必须具有相同的值。列表2-12显示如何在MyWidget类中实现isEqual:方法。

重载isEqual:方法

  1. - (BOOL)isEqual:(id)other {  
  2.  if (other == self)   
  3.  return YES;  
  4.  if (!other || ![other isKindOfClass:[self class]])  
  5.  return NO;  
  6.  return [self isEqualToWidget:other];  
  7. }  
  8.  
  9. - (BOOL)isEqualToWidget:(MyWidget *)aWidget {  
  10.  if (self == aWidget)  
  11.  return YES;  
  12.  if (![(id)[self name] isEqual:[aWidget name]])  
  13.  return NO;  
  14.  if (![[self data] isEqualToData:[aWidget data]])  
  15.  return NO;  
  16.  return YES;  

isEqual:方法首先检查指针的等同性,然后是类的等同性,最后调用对象的比较器进行比较。比较器的名称指示出参与比较的对象的类名称。这种类型的比较器对传入的对象进行强制类型检查,是Cocoa中常见的约定,NSString的isEqualToString:和NSTimeZone的isEqualToTimeZone:就是两个这样的例子。特定类的比较器(在这个例子中是isEqualToWidget:)负责执行name和data变量的等同性。

Cocoa框架的所有isEqualToType:方法中,nil都不是正当的参数,这些方法的实现在接收到nil参数时会抛出例外。然而为了向后兼容,Cocoa框架中的isEqual:方法可以接收nil值,在这种情况下返回NO。


0 0
原创粉丝点击