项目开发过程中可能会有这种需求,某个可变数组不断地增加元素,同时我们需要判断新的元素是否已经在数组里,如果不在才添加该元素,否则丢弃。
基于以上的需求,很容易想到使用NSArray的containsObject方法。我们先来看看官方的介绍:
- (BOOL)containsObject:(ObjectType)anObject
Parameters
anObject
An object.
Return Value
YES if anObject is present in the array, otherwise NO.
Discussion
Starting at index 0, each element of the array is passed as an argument to an isEqual: message sent to anObject until a match is found or the end of the array is reached. Objects are considered equal if isEqual: (declared in the NSObject protocol) returns YES.
对于普通的NSObject比较用isEqual:方法比较hash,而对于对于自己定义的类,直接使用containsObject会一直返回NO,原因是containsObject比较的是数组里的两个对象,其hash值必然不一样。比如以下自定义类:
@interface Person
@property NSString *name;
@property NSInteger age;
@end
@implementation Person
@end
Person中包含name和age,分别表示名字和年龄,数组中包含多个Person,我们的目的是,如果数组中存在同样的人名,并且年龄完全相同,就舍弃新的Person,如何实现这个需求呢?我们需要重载isEqual方法。
- (BOOL)isEqualToPerson:(Person *)person {
if (!person) {
return NO;
}
BOOL bIsEqualNames = (!self.name && !person.name) || [self.name isEqualToString:person.name];
BOOL bIsEqualAges = self.age == person.age;
return bIsEqualNames && bIsEqualAges;
}
#pragma mark - 重载isEqual方法
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Person class]]) {
return NO;
}
return [self isEqualToPerson:(Person *)object];
}
通过重载后,containsObject方法就能完美实现我们想要的功能。那么问题来了,像以下代码,会存在什么问题?
NSMutableArrray *personArray = [[NSMutableArray alloc] init] ;
...
在某个controller中初始化了数组,该controller注册了某个通知,有其他类每隔一定时间发送通知给controller,通知里包含person对象。当前controller收到通知后,通过containObject方法过滤重复的person,然后保存到personArray 中。
通知的处理函数如下:
-(void)didReceiveNotification:(id)sender
{
...
Person *newPerson = [[sender userInfo] objectFor:@"person" ];//此处取出通知中的person对象
...(做一些其他运算)
if(![personArray containsObject:newPerson ])
{
[personArray addObject:newPerson];
}
}
之后大家猜想,假设personArray保存了多个person,那么这些person的是不是能达到预期,name和age都不同,大家猜猜看?