对象等同性atom
不管咱们使用什么语言,老是会出现须要判断两个对象是否相等的状况,OC固然也不例外。首先看一段代码:spa
NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding]; NSString *str2 = @"equal"; if(str1 == str2) { NSLog(@"equal"); }
很明显,在咱们开来,str1和str2是“相等的”。可是事实上equal是不会被打印的。这是由于若是咱们直接比较两个对象是否相等,实际上比较的是两个对象的指针是否相等。指针
上述代码中str1和str2是分别指向两块不一样的内存的,因此确定不会像等了。code
咱们稍微修改一下代码再看看:对象
NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding]; NSString *str2 = @"equal"; if([str1 isEqual:str2]) { NSLog(@"equal"); }
注意看加粗语句,咱们改用NSObject提供的isEqual方法比较,发现"equal"被打印了出来。由于isEqual在NSString 内部被实现的时候比较的是真正的字符串是否相等!blog
对象等同性实现内存
看过上面例子后,如今咱们本身建立一个类来进一步说明等同性字符串
#import <Foundation/Foundation.h> @interface EqualObject : NSObject @property(nonatomic ,strong)NSString *name; @end #import "EqualObject.h" @implementation EqualObject @end
定义了一个EqualObject类,有一个name属性。hash
如今咱们建立两个对象来比较一下:it
EqualObject *object1 = [EqualObject new]; EqualObject *object2 = [EqualObject new]; if([object1 isEqual:object2]) { NSLog(@"equal"); }
发现代码运行结束并无输出"equal",缘由就在于isEqual方法是须要咱们本身实现的。NSObject的isEqual:方法默认是比较两个对象指向的地址是否相等,这里开辟了两个对象确定不想等了。
如今咱们添加isEqual:方法的实现:
-(BOOL)isEqual:(id)object { if([self class] == [object class]) { if(![self.name isEqual:[(EqualObject *)object name]]) { return NO; } return YES; } else { return [super isEqual:object]; } }
这里稍微解释一下,为何两个对象不一样类就调用父类的isEqual:这是由于,有的时候咱们是可让子类等于父类的,咱们只须要关注属性是否相同时能够这样写,若是不须要也能够不在父类处理那么久默认不相等了。
如今咱们不对name进行赋值操做依然是没有值打印出来的。
修改客户端代码:
EqualObject *object1 = [EqualObject new]; EqualObject *object2 = [EqualObject new]; object1.name = @"xiaoming"; object2.name = @"xiaoming"; if([object1 isEqual:object2]) { NSLog(@"equal"); }
发现这时候在运行就已经相等了。
为类定制等同性方法
咱们能够看到NSString除了能够用isEqual比较是否相等意外,还可使用isEqualToString来比较!这是专为NSString类定制的等同性方法,提供这样的方法就能够很明确咱们实现了该对象的isEqual方法。
下面为EqualObject提供定制的等同性方法,并修改isEqual:方法
- (BOOL)isEqualToEqualObject:(EqualObject *)object { if(self == object) return YES; if(![self.name isEqualToString:object.name]) return NO; return YES; } - (BOOL)isEqual:(id)object { if([self class] == [object class]) { return [self isEqualToEqualObject:object]; } else { return [super isEqual:object]; } }
而后客户端修改
if([object1 isEqualToEqualObject:object2]) { NSLog(@"equal"); }
很顺利的"equal"了...
对象hash码
每个OC对象内部都是有一个hash码的,当对象存入集合中(Array,Set,HashTable等),那么他们的hash码会被当作键来决定他们该放入哪个集合中。
首先咱们先看一下集合内部是如何存储的
hashCode | subCollection |
code1 | value1,value2,value3,value4 |
code2 | value5,value6 |
code3 | value7 |
code4 | value8,value9,value10 |
集合的内部并不像咱们所想的那样,是一个hash表,它将插入的对象根据hashCode来决定放入哪个子集合。若是要删除或者比较集合内元素,它首先根据hashCode找到子集合,而后跟子集合的每一个元素比较。
因此若是咱们的对象的hashCode若是都相同,那么就会出现严重的效率问题,
理论上来讲,咱们肯定等同性的两个对象的hash应该是相同的而不等的两个对象hash也应该不等,这样在存入hashTable之类的集合时,就会避免相同对象的重复添加,好比咱们两个对象hash相等,但实际对象不等,那么添加的时候就会被添加到同一subCollection下面。
因此为了不这种状况,咱们尽可能本身实现一种避免重复的方式,
这里提供一种,添加一个新属性age,hash实现以下:
- (NSUInteger)hash { NSUInteger nameHash = [_name hash]; NSUInteger ageHash = _age; return nameHash ^ ageHash; }
集合中的对象等同性
咱们对NSArray调用isEqual方法,它会对集合里的每一个对象和另外一个集合相同位置的对象进行isEqual:操做,只有所有相等,两个集合才相等。
这里说一下,集合里面最后添加都是不可变元素,若是是可变性元素会出现不法控制的状况。
好比咱们往NSSet里面添加两个NSMutableArray,一开始两个array不等,那么set中就有两个元素。
而后修改一个array使两个相等,这是set中就会有两个相等的元素存在!