NSMutableSet содержит дубликаты - PullRequest
5 голосов
/ 28 февраля 2012

У меня есть собственный класс с именем card, и мне нужно создать набор из 10 уникальных карт из массива карт случайного размера.Кроме того, мне нужно сначала включить все карты из белого списка, чтобы они всегда были включены.

Моя проблема в том, что карты из белого (и только белого) списка потенциально дублируются в наборе.Карты, добавленные случайным образом, никогда не дублируются, и их количество всегда верно (10).Я не могу понять, почему isEqual иногда кажется работающим, но не всегда.

Здесь я создаю набор (randoms - это массив потенциальных карт, из которых можно выбрать):

NSMutableSet *randomCards = [NSMutableSet setWithCapacity:10];

[randomCards addObjectsFromArray:whiteListArray];

while ([randomCards count] < 10) {
    NSNumber *randomNumber = [NSNumber numberWithInt:(arc4random() % [randoms count])];
    [randomCards addObject:[randoms objectAtIndex:[randomNumber intValue]]];
}

Я переопределил метод isEqual для своего класса card, основываясь на другом ответе здесь:

- (BOOL)isEqual:(id)other {

if (other == self)
    return YES;
if (!other || ![other isKindOfClass:[self class]])
    return NO;
return [self isEqualToCard:other];

}

- (BOOL)isEqualToCard:(Card *)myCard {

if (self == myCard) {
    return YES;
}
if ([self cardName] != [myCard cardName] && ![(id)[self cardName] isEqual:[myCard cardName]])
    return NO;

return YES;
}

Кажется, он работает отлично, за исключением случаев, когда я добавляю в карты белого списка, яне могу понять, как я получаю дубликаты (но не более 2-х копий).

1 Ответ

16 голосов
/ 28 февраля 2012

Вам необходимо переопределить hash в дополнение к isEqual.

Фактически, вы всегда должны убедиться, что эти два метода работают вместе. Из документации Apple :

Если два объекта равны (как определено методом isEqual:), они должны иметь одинаковое значение хеш-функции. Этот последний пункт особенно важен, если вы определяете хеш в подклассе и намереваетесь поместить экземпляры этого подкласса в коллекцию.

Примерно так должно работать:

- (NSUInteger)hash {
    return [[self cardName] hash];
}

Таким образом, ваш хеш зависит от той же информации, которую вы используете для сравнения.

Хэш используется структурами данных, такими как NSMutableSet, для быстрой группировки объектов в разные сегменты. Важно, что если два объекта равны, они имеют одинаковое хеш-значение. (Это нормально, однако, если два объекта имеют одинаковый хэш, но не равны. Поэтому вы всегда можете вернуть одно и то же число из hash, но тогда ваша производительность будет такой же, как при использовании массива. Структуры данных!)

...