关于isEqual
的使用(isEqualTo
内部调用的是isEqual
),不同的调用者有不同的实现方式。
自定义对象类型调用
查看runtime的源码,在NSObject
类中可以找到实现,本质是判断是否为同一个对象(内存地址相同),内部使用的是==
+ (BOOL)isEqual:(id)obj {
return obj == (id)self;
}
- (BOOL)isEqual:(id)obj {
return obj == self;
}
如果想要自定义,需要重写isEqual
方法和hash
,如果两个对象相等,则它们都具有相同的哈希值,重写hash
方法时,应该让每一个成员都参与进来,可以使用下面写法,仅供参考:
- (BOOL)isEqualToRSWorker:(RSWorker *)worker {
if (!worker) {
return NO;
}
if ( self.age == worker.age && [self.name isEqualToString:worker.name] && [self.no isEqualToString:worker.no] ) {
return YES;
}
return NO;
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:self.class]) {
return NO;
}
return [self isEqualToRSWorker:(RSWorker *)object];
}
- (NSUInteger)hash {
return self.name.hash^self.no.hash^self.age;
}
非自定义对象类型调用
NSArray,NSDictionary,NSString,NSSet等不同的数据类型会有不同的实现,虽然苹果的Foundation不开源,我们可以通过汇编去跟,或者直接找GNUstep,看代码实现
NSArray
首先判断是否为相同对象==
,然后判断如果都是数组类型,则调用isEqualToArray
,判断元素个数,然后每一个元素调用isEqual
判断是否相等。
- (BOOL) isEqual: (id)anObject
{
if (self == anObject)
return YES;
if ([anObject isKindOfClass: NSArrayClass])
return [self isEqualToArray: anObject];
return NO;
}
- (BOOL) isEqualToArray: (NSArray*)otherArray
{
NSUInteger i, c;
if (self == (id)otherArray)
return YES;
c = [self count];
if (c != [otherArray count])
return NO;
if (c > 0)
{
IMP get0 = [self methodForSelector: oaiSel];
IMP get1 = [otherArray methodForSelector: oaiSel];
for (i = 0; i < c; i++) {
if (![(*get0)(self, oaiSel, i) isEqual: (*get1)(otherArray, oaiSel, i)])
return NO;
}
}
return YES;
}
NSData
首先判断是否==
,然后判断长度,然后对比每一个字节
- (BOOL) isEqual: anObject
{
if ([anObject isKindOfClass: [NSData class]])
return [self isEqualToData: anObject];
return NO;
}
- (BOOL) isEqualToData: (NSData*)other
{
NSUInteger len;
if (other == self)
{
return YES;
}
if ((len = [self length]) != [other length])
{
return NO;
}
return (memcmp([self bytes], [other bytes], len) ? NO : YES);
}
NSDictionary
首先判断是否==
,然后判断如果都是NSDictionary
类型,则调用isEqualToDictionary
,判断元素个数,然后通过key
取出value
,value
调用isEqual
判断是否相等。
- (BOOL) isEqual: other
{
if (other == self)
return YES;
if ([other isKindOfClass: NSDictionaryClass])
return [self isEqualToDictionary: other];
return NO;
}
- (BOOL) isEqualToDictionary: (NSDictionary*)other
{
unsigned count;
if (other == self)
{
return YES;
}
count = [self count];
if (count == [other count])
{
if (count > 0)
{
NSEnumerator *e = [self keyEnumerator];
IMP nxtObj = [e methodForSelector: nxtSel];
IMP myObj = [self methodForSelector: objSel];
IMP otherObj = [other methodForSelector: objSel];
id k;
while ((k = (*nxtObj)(e, @selector(nextObject))) != nil)
{
id o1 = (*myObj)(self, objSel, k);
id o2 = (*otherObj)(other, objSel, k);
if (o1 == o2)
continue;
if ([o1 isEqual: o2] == NO)
return NO;
}
}
return YES;
}
return NO;
}