iOS使用containsObject的那些坑
阿新 • • 發佈:2019-01-30
專案開發過程中可能會有這種需求,某個可變陣列不斷地增加元素,同時我們需要判斷新的元素是否已經在數組裡,如果不在才新增該元素,否則丟棄。
基於以上的需求,很容易想到使用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;
<pre name="code" class="objc" style="font-size: 13.3333px;">@end
@implementation Person@end
Person中包含name和age,分別表示名字和年齡,陣列中包含多個Person,我們的目的是,如果陣列中存在同樣的人名,並且年齡完全相同,就捨棄新的Person,如何實現這個需求呢?我們需要過載isEqual方法通過過載後,containsObject方法就能完美實現我們想要的功能。那麼問題來了,像以下程式碼,會存在什麼問題?- (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]; }
<span style="font-size: 13.3333px;">NSMutableArrray *personArray = [[NSMutableArray alloc] init] ;
...
</span>
<span style="font-size: 13.3333px;">在某個controller中初始化了陣列,該controller註冊了某個通知,有其他類每隔一定時間傳送通知給controller,通知裡包含person物件。當前controller收到通知後,通過containObject方法過濾重複的person,然後儲存到personArray 中。
通知的處理函式如下:
</span>
-(void)didReceiveNotification:(id)sender
{
...
Person *newPerson = [[sender userInfo] objectFor:@"person" ];//此處取出通知中的person物件
...(做一些其他運算)
if(![personArray containsObject:newPerson ])
{
[personArray addObject:newPerson];
}
}
之後大家猜想,假設personArray儲存了多個person,那麼這些person的是不是能達到預期,name和age都不同,大家猜猜看?
如果您對我的文章感興趣,請關注我的公眾號"充電實踐",希望在網際網路的道路上我們並肩前行。