9

C'è qualche ragione particolare per cui il tentativo di memorizzare e recuperare un valore in un NSMutableDictionary utilizzando un NSIndexPath come key potrebbe non riuscire?Problemi con NSIndexPath come chiave in NSMutableDictionary?

All'inizio ho cercato di fare questo al fine di memorizzare un NSMutableDictionary di UITableViewCell altezze (self.cellHeights) per un UITableView. Ogni volta che si batté un UITableViewCell, quella cella sarebbe o espandere o contratto tra due altezze diverse in base al valore memorizzato nel NSMutableDictionary per quel particolare 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]; 
} 

Per ragioni a me sconosciute, ottenendo l'altezza della cella all'interno tableView:didSelectRowAtIndexPath: via [self.cellHeights objectForKey:indexPath] funziona bene. Tuttavia, il tentativo di ottenere l'altezza della cella entro tableView:heightForRowAtIndexPath: tramite [self.cellHeights objectForKey:indexPath] restituisce sempre nulla perché sembra che l'indicePath utilizzato per archiviare l'altezza non corrisponda al parametro IndexPath utilizzato per recuperare l'altezza della cella, anche se hanno gli stessi valori per indexPath.section e indexPath.row. Per questo motivo, un nuovo oggetto per lo stesso "index" index path viene aggiunto a self.cellHeights (come evidente dal self.cellHeights.count incrementi successivi).

Questo fa non accadere quando si memorizzano le altezze delle celle nella NSMutableDictionary utilizzando la riga ([NSNumber numberWithInteger:indexPath.row]) come la chiave ... ed è quello che sto facendo per ora, ma mi piacerebbe capire perché indexPath non funziona come chiave.

risposta

1

ci sono diverse cose che devono essere attuate per un oggetto di lavorare in modo affidabile come chiave per NSDictionary, vale a dire isEqual:, hash e Copyable protocollo.

Non sono molto sicuro che NSIndexPath sia mai stato concepito come chiave per i dizionari (perché è stato creato come indice per gli array).

La mia ipotesi è che hash non sia implementato correttamente per diverse istanze della classe. Si noti inoltre che alcuni dei metodi delegati della tabella vengono chiamati con NSIndexPath e alcuni con NSMutableIndexPath. Questo probabilmente sta facendo la differenza.

12

Anche se sono in ritardo nella discussione, ecco una soluzione rapida e semplice che consente di utilizzare istanze NSIndexPath come chiavi del dizionario.

Proprio ricreare l'indexPath aggiungendo la seguente riga:

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

Voilà. tableView:heightForRowAtIndexPath: utilizza internamente le istanze NSMutableIndexPath (come vedresti con un punto di interruzione). In qualche modo queste istanze sembrano non collaborative con NSIndexPath quando si calcolano le chiavi di hash.

Convertendolo di nuovo a NSIndexPath, quindi tutto funziona.

+0

Holy Moly. Questo era GUIDARE ME MAD. Per ore ho iniziato a pettinare internet cercando di capire perché il mio dizionario stava restituendo nil per un indicePath I KNEW esistito. Assolutamente esasperante. GRAZIE per la pubblicazione. – Andy

3

@ La risposta di Jean sembra accettabile, ma la questione è stata answered in more detail here. In breve, UITableView volte usa le istanze di NSMutableIndexPath invece di NSIndexPath e le istanze di queste due classi non sono mai uguali perché [NSMutableIndexPath class] != [NSIndexPath class].La soluzione è quello di generare sempre una chiave NSIndexPath per qualsiasi cosa che si basa su isEqual o hash, come ad esempio la ricerca chiavi del dizionario:

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