Проблемы с использованием NSIndexPath как ключа в NSMutableDictionary?
Есть ли какая-либо особая причина, по которой попытка сохранить и получить значение в NSMutableDictionary
с помощью NSIndexPath
, поскольку key
может завершиться с ошибкой?
Я изначально попытался сделать это, чтобы сохранить NSMutableDictionary
высот UITableViewCell
(self.cellHeights
) для UITableView
. Каждый раз, когда вы нажимаете UITableViewCell
, эта ячейка будет либо расширяться, либо сокращаться между двумя разными высотами на основе значения, хранящегося в NSMutableDictionary
для этого конкретного indexPath
:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *heightNSNumber = [self.cellHeights objectForKey:indexPath];
if (!heightNSNumber)
{
heightNSNumber = [NSNumber numberWithFloat:100.0];
[self.cellHeights setObject:heightNSNumber forKey:indexPath];
}
return [heightNSNumber floatValue];
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSNumber *heightNSNumber = [self.cellHeights objectForKey:indexPath];
if (!heightNSNumber)
{
heightNSNumber = [NSNumber numberWithFloat:100.0];
[self.cellHeights setObject:heightNSNumber forKey:indexPath];
}
if ([heightNSNumber floatValue] == 100.0)
{
[self.cellHeights setObject:[NSNumber numberWithFloat:50.0]
forKey:indexPath];
} else {
[self.cellHeights setObject:[NSNumber numberWithFloat:100.0]
forKey:indexPath];
}
[tableView beginUpdates];
[tableView endUpdates];
}
По неизвестным мне причинам, высота ячейки внутри tableView:didSelectRowAtIndexPath:
через [self.cellHeights objectForKey:indexPath]
работает просто отлично. Тем не менее, попытка получить высоту ячейки внутри tableView:heightForRowAtIndexPath:
через [self.cellHeights objectForKey:indexPath]
всегда возвращает nil, потому что кажется, что indexPath, используемый для хранения высоты, не соответствует индексу, который используется для извлечения высоты ячейки, даже если они имеют одинаковые значения для indexPath.section
и indexPath.row
. Из-за этого к self.cellHeights
добавляется новый объект для "одинакового" пути указателя (как видно, так как self.cellHeights.count
увеличивается после этого).
Это не происходит, когда вы храните высоты ячеек в NSMutableDictionary, используя строку ([NSNumber numberWithInteger:indexPath.row]
) в качестве ключа... так, что я делаю это сейчас, но я хотел бы понять, почему indexPath
не работает как ключ.
Ответы
Ответ 1
Хотя я опаздываю в обсуждении, вот быстрое и простое решение, которое позволит вам использовать экземпляры NSIndexPath в качестве словарных ключей.
Просто воссоздайте indexPath, добавив следующую строку:
indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
Вуаля. tableView:heightForRowAtIndexPath:
использует внутренние экземпляры NSMutableIndexPath
(как вы бы видели с точкой останова). Как-то эти экземпляры кажутся несогласованными с NSIndexPath
при вычислении хеш-ключей.
Преобразуя его обратно в NSIndexPath
, тогда все работает.
Ответ 2
@Ответ на вопрос представляется приемлемым, но этот вопрос был более подробно рассмотрен здесь. Короче говоря, UITableView
иногда использует экземпляры NSMutableIndexPath
вместо NSIndexPath
, а экземпляры этих двух классов никогда не равны, потому что [NSMutableIndexPath class] != [NSIndexPath class]
. Обходной путь состоит в том, чтобы всегда генерировать ключ NSIndexPath
для всего, что полагается на isEqual
или hash
, например, поиск ключей словаря:
- (NSIndexPath *)keyForIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath class] == [NSIndexPath class]) {
return indexPath;
}
return [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
}
Ответ 3
Существует несколько вещей, которые должны быть реализованы для надежной работы объекта в качестве ключа для NSDictionary
, а именно протокола isEqual:
, hash
и Copyable
.
Я не очень уверен, что NSIndexPath
когда-либо намерен работать как ключ к словарям (потому что он был индексом для массивов).
Я предполагаю, что hash
не выполняется правильно для разных экземпляров класса. Также обратите внимание, что некоторые из методов делегата таблицы вызываются с помощью NSIndexPath
, а некоторые - с NSMutableIndexPath
. Возможно, это имеет значение.