помогите с isEquals и хэшем в iphone - PullRequest
5 голосов
/ 01 июля 2011

Так что я переопределяю isEquals и hash для сравнения пользовательских объектов, чтобы иметь возможность удалять дубликаты из NSArray.Проблема в том, что я пропускаю некоторые значения в списке, который не содержит дублирующихся элементов, и кажется, что моя реализация hash или isEquals неверна.Пользовательский объект - это объект Course, который имеет некоторые переменные, такие как: id и name Я поместу код здесь:

- (BOOL)isEqual:(id)object {
    if ([object isKindOfClass:[Course self]]) {
        return YES;
    } 
    if(self == object){
        return YES;
    }
    else {
        return NO;
    }
}

- (unsigned)hash {

    NSString *idHash = [NSString stringWithFormat: @"%d", self._id];
    return [idHash hash];
}

Затем, после запроса к базе данных, я поместил значения в массиви затем в наборе, который должен удалить дублирующиеся элементы, как это:

NSMutableSet *noDuplicates = [[NSMutableSet alloc] initWithArray:tempResults];

Можете ли вы увидеть, что я делаю неправильно в реализации isEquals или hash?

Большое спасибо.

Ответы [ 4 ]

11 голосов
/ 01 июля 2011

Шаг 1. Решите, какие переменные / состояние экземпляра используются для определения равенства.Рекомендуется убедиться, что свойства для них существуют (они могут быть частными свойствами, объявленными в расширении класса , если хотите).

Шаг 2. Напишите хеш-функцию на основе этих переменных экземпляра.Если все свойства, которые учитываются, являются объектами, вы можете просто скопировать их хэши вместе.Вы также можете напрямую использовать C-объекты и т. Д.

Шаг 3. Запись isEqual: Нормальный шаблон, вероятно, сначала проверяет, что оба объекта находятся в классе или подклассе метода, в котором определено isEqual:а затем проверить равенство для всех свойств.

Так, если у класса Person есть свойство name (тип NSString) и свойство number (тип int), которые вместе определяют уникального персонажа, hash может быть:

-(NSUInteger) hash
{
    return [[self name] hash] ^ [self number];
}

isEqual: может быть

-(BOOL) isEqual: (id) rhs
{
    BOOL ret = NO;
    if ([rhs isKindOfClass: [Person class]]) // do not use [self class]
    {
        ret = [[self name] isEqualToString: [rhs name]] && [self number] == [rhs number];
    } 
    return ret;
}

Я не думаю, что это указано как явное требование в документе, но, вероятно, предполагается, что равенство симметрично и транзитивно, т. Е.

  • [a isEqual: b] == [b isEqual: a] для всех a и b
  • [a isEqual: b] && [b isEqual: c] подразумевает [a isEqual: c] для всех a, b, c

Поэтому вам следует быть осторожным, если вы переопределите isEqual: для подклассовчтобы убедиться, что это работает в обе стороны.Это также, почему комментарий, не используйте [self class] выше.

3 голосов
/ 01 июля 2011

Что ж, ваша реализация isEqual: на самом деле просто проверяет, являются ли два объекта одним и тем же классом. Это совсем не правильно. Не зная деталей вашего объекта, я не знаю, как будет выглядеть хорошая реализация, но, вероятно, она будет следовать структуре

- (BOOL)isEqual:(id)object {
    if ([object isMemberOfClass:[self class]]) {
        // test equality on all your important properties
        // return YES if they all match
    }
    return NO;
}

Точно так же ваш хеш основан на преобразовании int в строку и получении его хеша. Вы также можете просто вернуть сам int как ваш хеш.

2 голосов
/ 02 марта 2013

Ваш код нарушает принцип "равные объекты должны иметь одинаковые хэши".Ваш хеш-метод генерирует хеш из self._id и не учитывает это значение при оценке равенства объектов.

Основные понятия в программировании Objective-C содержит раздел, посвященный самоанализугде эта тема имеет примеры и освещение.isEqual предназначен для ответа на вопрос, являются ли два объекта эквивалентными, даже если они представляют собой два разных экземпляра.Таким образом, вы хотите вернуть BOOL, указывающий, следует ли считать объект эквивалентным.Если вы не реализуете isEqual, он просто сравнит указатель на равенство, а это не то, что вам, вероятно, нужно.

- (BOOL)isEqual:(id)object {
    BOOL result = NO;

    if ([object isKindOfClass:[self class]]) {
        result = [[self firstName] isEqualToString:[object firstName]] && 
        [[self lastName] isEqualToString:[object lastName]] &&
        [self age] == [object age];
    }

    return result;
}

Из справочника NSObject :

Возвращает целое число, которое можно использовать в качестве адреса таблицы в структуре хеш-таблицы.

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

- (NSUInteger)hash {
    NSUInteger result = 1;
    NSUInteger prime = 31;

    result = prime * result + [_firstName hash];
    result = prime * result + [_lastName hash];
    result = prime * result + _age;

    return result;
}

Итак, что определяет два равных объекта, определяется программистом иих потребности.Однако, независимо от того, какая методология равенства разработана, равные объекты должны иметь одинаковые хэши.

0 голосов
/ 01 июля 2011

это то, как вы реализуете хеш и isEqual (по крайней мере тот, который работает для меня с целью выявления дубликатов)

Функция хеширования

В Apple Doc сказано, что хэш двух объектов должен быть одинаковым для тех, которые считаются равными (логически). следовательно, я бы реализовал хеш, как показано ниже

-(unsigned int)hash  
{  
    return 234;//some random constant  
} 

isEqual: реализация метода будет выглядеть примерно так:

-(BOOL)isEqual:(id)otherObject  
{  
  MyClass *thisClassObj = (MyClass*)otherObject;

  *// this could be replaced by any condition statement which proves logically that the two object are same even if they are two different instances* 

return ([thisClassObj primaryKey] == [self primaryKey]);

}

Дополнительная ссылка здесь: Методы реализации -hash для изменяемых объектов Какао

Реализация -hash / -isEqual: / -isEqualTo ...: для коллекций Objective-C

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...