对象的比较
hash
和isEqual:
方法虽然不是严格的内省方法,但是可以发挥类似的作用,是进行对象的识别和比较时不可或缺的运行时工具。它们并不向运行环境查询对象信息,而是依赖于具体类的比较逻辑。
hash
和isEqual:
方法都在NSObject
协议中声明,且彼此关系紧密。实现hash
方法必须返回一个整型数,作为哈希表结构中的表地址。两个对象相等(isEqual:
方法的判断结果)意味着它们有相同的哈希值。如果您的对象可能被包含在象NSSet这样的集合中,则需要定义hash
方法,并确保该方法在两个对象相等的时候返回相同的哈希值。NSObject
类中缺省的isEqual:
实现只是简单地检查指针是否相等。
isEqual:
的使用相当直接,它将消息的接收者和通过参数传入的对象进行比较。对象的比较常常可以在运行时决定应该对对象做些什么。如列表2-11所示,您可以通过isEqual:
来确定是否执行某一个动作。在这个例子中,动作是指保存被修改了的预置信息。
列表2-11 使用isEqual:方法
- (void)saveDefaults { |
NSDictionary *prefs = [self preferences]; |
if (![origValues isEqual:prefs]) |
[Preferences savePreferencesToDefaults:prefs]; |
} |
如果您正在创建子类,则可能需要重载isEqual:
方法,以进一步检查对象是否相等。子类可能定义额外的属性,当两个实例被认为相等时,属性的值必须相同。举例来说,假定您创建一个名为MyWidget的NSObject子类,类中包含两个实例变量:name
和data
。当MyWidget的两个实例被认为是相等时,这些变量必须具有相同的值。列表2-12显示如何在MyWidget类中实现isEqual:
方法。
列表 2-12 重载isEqual:方法
- (BOOL)isEqual:(id)other { |
if (other == self) |
return YES; |
if (!other || ![other isKindOfClass:[self class]]) |
return NO; |
return [self isEqualToWidget:other]; |
} |
|
- (BOOL)isEqualToWidget:(MyWidget *)aWidget { |
if (self == aWidget) |
return YES; |
if (![(id)[self name] isEqual:[aWidget name]]) |
return NO; |
if (![[self data] isEqualToData:[aWidget data]]) |
return NO; |
return YES; |
} |
isEqual:
方法首先检查指针的等同性,然后是类的等同性,最后调用对象的比较器进行比较。比较器的名称指示出参与比较的对象的类名称。这种类型的比较器对传入的对象进行强制类型检查,是Cocoa中常见的约定,NSString的isEqualToString:
和NSTimeZone的isEqualToTimeZone:
就是两个这样的例子。特定类的比较器(在这个例子中是isEqualToWidget:
)负责执行name和data变量的等同性。
在Cocoa框架的所有isEqualTo
Type:
方法中,nil
都不是正当的参数,这些方法的实现在接收到nil
参数时会抛出例外。然而为了向后兼容,Cocoa框架中的isEqual:
方法可以接收nil
值,在这种情况下返回NO
。