fabian789
fabian789

Reputation: 8412

Weird duplicated keys in NSDictionary on iOS 5, not so on iOS 6

I'm using a NSMutableDictionary to store some values about some UITableViewCells, so I'm using instances of NSIndexPath as keys. Everything works as expected on iOS 6, but when I run the exact same code in the iOS 5 Simulator, weird things happen. So I printed the contents of the dictionary to the console:

Printing description of heights:
{
    "<UIMutableIndexPath 0x6a8a3d0> 2 indexes [1, 3]" = 100;
    "<UIMutableIndexPath 0x6a8a3d0> 2 indexes [1, 3]" = 100;
    "<UIMutableIndexPath 0x6a8a3d0> 2 indexes [1, 3]" = 100;
}

On iOS 6 it looks like this:

Printing description of heights:
{
    "<UIMutableIndexPath 0x75ca8c0> 2 indexes [0, 1]" = 44;
    "<UIMutableIndexPath 0x75caa70> 2 indexes [0, 0]" = 10;
    "<UIMutableIndexPath 0x75ca500> 2 indexes [1, 0]" = 100;
    "<UIMutableIndexPath 0x717df70> 2 indexes [1, 1]" = 67;
    "<UIMutableIndexPath 0x715a3e0> 2 indexes [1, 2]" = 67;
    "<UIMutableIndexPath 0x717def0> 2 indexes [1, 3]" = 67;
}

Which is how it should be, obviously! Why would the dictionary on iOS 5 store different values for exactly the same key?


Edit: Some code...

The dictionary creating is just

self.heights = [[NSMutableDictionary alloc] init];

I set values using the new subscripting syntax, i.e. like so:

self.heights[indexPath] = minHeight;

(indexPath is a NSIndexPath, minHeight is a NSNumber.)

I set these values dynamically as the delegate requests them:

- (NSNumber *)heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (![indexPath isInTableView:self.tableView])
    {
        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"indexPath not in tableView" userInfo:nil];
    }

    NSNumber *storedHeight = self.heights[indexPath];
    if (storedHeight != nil)
    {
        return storedHeight;
    }

    NSNumber *minHeight = self.minimumHeights[indexPath];
    self.heights[indexPath] = minHeight;
    return minHeight;
}

The minimumHeights NSDictionary also holds NSNumbers for every indexPath in a table view.

Upvotes: 2

Views: 516

Answers (1)

djromero
djromero

Reputation: 19641

I remember reading about NSIndexPath methods isEqual: or hash or both changing in iOS6 or just that there was a bug in iOS 5. In any case, it seems you can't use them as dict keys.

Try using different keys. Maybe using its description method or a custom string built with the section and row.

#define idx2key(_ip) [NSString stringWithFormat:@"%d:%d", [_ip section], [_ip row]]

...
self.heights[idx2key(indexPath)] = minHeight;
...

In old NSIndexPath Apple said:

NSIndexPath objects are uniqued and shared. If an index path containing the specified index or indexes already exists, that object is returned instead of a new instance.

That paragraph doesn't exist anymore. I guess internal comparison of instances have been changed too.

Upvotes: 3

Related Questions