使用NSIndexPath作为NSMutableDictionary中的键的问题?

时间:2013-10-27 02:10:44

标签: objective-c cocoa-touch uitableview nsmutabledictionary nsindexpath

使用NSMutableDictionary作为NSIndexPath尝试在key中存储和检索值可能会失败,是否有任何特殊原因?

我最初尝试执行此操作,以便为NSMutableDictionary存储UITableViewCell self.cellHeights个高度(UITableView)。每次点击UITableViewCell时,该单元格将根据NSMutableDictionaryindexPath存储的值,在两个不同高度之间展开或收缩:

- (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不匹配,即使它们对indexPath.sectionindexPath.row具有相同的值。因此,self.cellHeights添加了一个“相同”索引路径的新对象(此后self.cellHeights.count增加,因此显而易见)。

当您使用行([NSNumber numberWithInteger:indexPath.row])作为键将单元格高度存储在NSMutableDictionary中时,会发生这种情况......这就是我现在正在做的事情,但是我想了解为什么indexPath没有成为关键。

3 个答案:

答案 0 :(得分:13)

虽然我讨论的时间较晚,但这是一个快速而简单的解决方案,允许您将NSIndexPath实例用作字典键。

只需重新创建 indexPath,方法是添加以下行:

indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];

瞧。 tableView:heightForRowAtIndexPath:在内部使用NSMutableIndexPath个实例(正如您在断点处看到的那样)。不知何故,这些实例在计算哈希键时似乎与NSIndexPath不合作。

通过将其转换回NSIndexPath,一切正常。

答案 1 :(得分:4)

@ Jean的答案似乎可以接受,但这个问题一直是answered in more detail here。简而言之,UITableView有时会使用NSMutableIndexPath而不是NSIndexPath的实例,而这两个类的实例永远不会相等,因为[NSMutableIndexPath class] != [NSIndexPath class]。解决方法是始终为依赖NSIndexPathisEqual的任何内容生成密钥hash,例如查找字典密钥:

- (NSIndexPath *)keyForIndexPath:(NSIndexPath *)indexPath
{
    if ([indexPath class] == [NSIndexPath class]) {
        return indexPath;
    }
    return [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
}

答案 2 :(得分:1)

对象必须实现几件事才能可靠地作为NSDictionary的关键,即isEqual:hashCopyable协议。

我不太确定NSIndexPath是否有意成为词典的关键(因为它被作为数组的索引)。

我的猜测是hash未针对该类的不同实例正确实现。另请注意,某些表委托方法使用NSIndexPath调用,而某些调用NSMutableIndexPath调用。这可能会带来不同。