web-dev-qa-db-fra.com

Quelle est la signification du message "Aucun chemin d'index pour la cellule de table en cours de réutilisation" dans iOS 6/7?

Depuis que j'ai commencé à compiler mon application avec iOS 6 (et depuis iOS 7), j'ai commencé à voir ce message. Je sais que la façon dont UITableViews gère la gestion des cellules est différente dans iOS 6, mais je n'ai pas eu besoin de modifier mon code pour qu'il continue à fonctionner. Mais je crains que ce message n'indique un problème potentiel que je ne vois pas encore… Est-ce que quelqu'un peut nous éclairer?

57
Nathan Brown

J'ai commencé à avoir cette erreur dans le journal depuis iOS 7 bêta 5 et versions ultérieures, y compris dans la version iOS 7 GM/Release, alors que cela ne s'était jamais produit dans mon application sous iOS 6 ou dans les versions antérieures de iOS 7. Après de nombreuses expériences, j'ai trouvé la cause:

J'utilisais des objets UITableViewCell pour mes vues d'en-tête de section et les retournais dans tableView:viewForHeaderInSection:. Cela semble être une pratique courante, en particulier depuis iOS 5, lorsqu'il est devenu facile de concevoir une vue d'en-tête de section en tant que cellule de vue de tableau prototype dans un StoryBoard avec Interface Builder.

Lorsque j'ai modifié mon application pour n'utiliser que des sous-classes UIView ordinaires pour mes vues d'en-tête de section, les erreurs ont disparu et, plus important encore, ma vue de table a cessé de supprimer de manière aléatoire les en-têtes de section!

Il semblerait que (depuis iOS 7 bêta 5) UITableView maintienne en interne un mappage de tous les objets UITableViewCell dans sa hiérarchie de vues et de leurs chemins d’index respectifs. Comme un en-tête de section (ou un en-tête de table dans le pied de page) n’a pas de chemin d’index, si vous utilisez un objet UITableViewCell pour ces vues, la vue tableau deviendra confuse lorsqu’elle trouvera une UITableViewCell pour laquelle elle n’a pas de valeur. index path, entraînant l'erreur "aucun chemin d'index pour la cellule de tableau réutilisée" et, si vous êtes malchanceux, des problèmes d'affichage dans votre vue tableau:

UPDATE: si vous avez accès aux forums Apple Dev, voici le fil conducteur (que j'ai démarré): https://devforums.Apple.com/message/882042#882042

Comme suggéré dans ce fil de discussion, si vous ne souhaitez pas trop retarifier, vous pouvez créer un wrapper UIView autour de votre UITableViewCell et le retourner comme vue d'en-tête de section. 

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
[view addSubview:cell];

return view;

Notez cependant que cette approche "wrapper" UIView ne fonctionnera pas bien avec la mise en forme automatique et la rotation de périphérique. Je vous suggère donc d'utiliser une sous-classe UIView pour les cellules d'en-tête et de pied de page, et non une sous-classe UITableViewCell comme expliqué dans la partie principale de la réponse.

132
mluisbrown

Je renverrais le contentView de UITableViewCell au lieu de créer un wrapper ... en ayant en tête les contraintes jabble

return cell.contentView;
41
mar-schmidt

J'ai eu le même problème et il m'a fallu quelques heures pour traquer le problème. Il s'avère que j'appelais [textField becomeFirstResponder] lors de la configuration des cellules (ici, textField faisait partie d'une tableviewcell personnalisée); [textField becomeFirstResponder]in tourne la notification keyboardWillShow, ce qui a provoqué le chargement prématuré de la table, causant ainsi le message " aucun chemin d'index pour la réutilisation du message de cellule de table ". Une fois que j'ai supprimé cet appel, le problème a disparu.

26
mpprdev

En plus de la réponse acceptée (mluisbrown), je devais ajouter un masque de taille automatique à la cellule d’en-tête, car la mienne contenait une étiquette multiligne, c.-à-d.

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
cell.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[view addSubview:cell];
return view;
16
Rob

Il s'agit d'un bogue UIKit interne, comme mentionné dans les propres forums de développement d'Apple. C'est censé être corrigé dans les versions plus récentes de xcode, bien que je ne sois pas en mesure de trouver d'informations concernant la version qui corrige ce problème.

8
diegoreymendez

En complément de mon précédent article (dans lequel j'avais mentionné qu'il s'agissait apparemment d'un bogue avec UIKit), j'ai pu trouver une solution de contournement à mon cas particulier (dans lequel le message était lié à des problèmes de visualisation étranges sur la table).

Apparemment, le -(void)setEditing:animated: surchargé de ma cellule personnalisée mettait trop de temps à revenir.

Mon code précédent était:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];
    [self someAdditionalCode];
}

J'ai pu le réparer en le changeant en:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];

    // DRM: we want to perform the actions from this block in the main thread, but
    // asynchronously to avoid excessive delays which were causing issues.
    //
    dispatch_async(dispatch_get_main_queue(), ^void()
    {
        [self someAdditionalCode];
    });
}
4
diegoreymendez

Faire mes endupdates après resignfirstresponder résolu mon problème (avoir un UITextFIeld dans ma cellule personnalisée)

-(void)textfieldEditDone
{
....

    [textField resignFirstResponder];
    [self.tableView endUpdates];
2
Daniel Åkesson

J'ai eu le même problème avec le message d'erreur apparaissant. Autant que je sache, cela est dû au rechargement de la vue tableau à partir d'une fonction appelée par le champ de texte dans le cadre de son protocole de délégué. C'est-à-dire textFieldDidEndEditing -> [controller.tableview reload ...]

2
Dan

Pour mémoire, j'ai aussi rencontré ce message lorsque je travaillais sous iOS 6. Il semble que certains codes hérités ou importés avaient à peu près la même caractéristique:

(NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
    NSInteger rows = 0;
    if ([delegate respondsToSelector:@selector(numberOfItemsInSection:)]) {
        rows = [delegate numberOfItemsInSection:section];

        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

Lorsque la séquence beginUpdate:/endUpdate: a été supprimée, le problème a disparu comme par magie.

1
Fred The Bishop

C'est évidemment une vieille question, mais j'espère que cela peut aider tous ceux qui ont encore ce problème dans iOS8 +, car c'est toujours la question la plus fréquemment posée pour ce message d'erreur particulier.

J'utilisais PINRemoteImage pour télécharger de manière asynchrone une image sur un UIImageView se trouvant dans un UITableViewCell personnalisé.

Afin de redimensionner correctement la ligne (cellules de hauteur dynamiques utilisant la mise en page automatique) une fois l'image chargée, j'ai appelé:

self.tableView beginUpdates;
self.tableView endUpdates;

Je recevais alors le message "Aucun chemin d'index pour la cellule de table en cours de réutilisation" et l'application se bloquait. J'avais pensé que le bloc PINRemoteImageManagerResult se trouvait sur le thread principal, mais il s'est avéré que ce n'était pas le cas. Par conséquent, le fait de s'assurer que les mises à jour de début/fin étaient appelées résolvait le problème.

dispatch_async(dispatch_get_main_queue(), ^(void){
                            [self.tableView beginUpdates];
                            [self.tableView endUpdates];
});
1
siburb

Peut-être que cela aide quelqu'un: j’ai déjà eu cette erreur en rafraîchissant une seule cellule de la vue tableau. Je voulais faire quelque chose comme 

NSIndexPath *reloadRow = [NSIndexPath indexPathForRow:1 inSection:2];
[self._mainTableView reloadRowsAtIndexPaths:@[reloadWebViewRow]
                           withRowAnimation:UITableViewRowAnimationFade];

Mais accidentellement, j'ai tapé

NSIndexPath *reloadRow = [NSIndexPath indexPathForItem:1 inSection:2];

Notez la différence entre les deux chemins d'index: l'un est créé avec indexPathForItem (faux), l'autre avec indexPathForRow (correct). Tout cela a entraîné un comportement très étrange de la tableView et du message d'erreur dans le titre. 

0
Tobias

Il semble que mon problème ait été déclenché lorsque j'essayais de mettre à jour l'interface utilisateur dans une partie du code qui était un rappel d'un appel Web. J'ai résolu en forçant les mises à jour d'interface utilisateur à se produire sur le fil principal. J'ai utilisé un code comme celui-ci.

void runOnMainQueueWithoutDeadlocking(void (^block)(void)){
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

Je l’appelle comme suit dans le bloc de succès de mon appel Web en arrière-plan.

runOnMainQueueWithoutDeadlocking(^{
    [self.tableView beginUpdates];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
});
0
Brackston Mayhall

Encore une autre condition ...

Cela s'est produit lorsque, ne voulant pas d'en-tête, je suis retourné nil.

Réparer:

func tableView(tableView: UITableView,
               titleForHeaderInSection section: Int) -> String? {
    return ""
}
0
SwiftArchitect

Eh bien, j'ai passé presque toute la journée à essayer de résoudre ce problème. J'espère donc que cette explication alternative fera gagner du temps à quelqu'un d'autre.

J'ai eu une tableview qui donnait ce message parfois , lors du chargement. Cela s'est avéré être causé par les notifications KVO concernant le déclenchement d'objets Core Data pendant le chargement de la vue. (En observant une modification, mon contrôleur a essayé d'appeler reloadData sur la vue de table en question. Ce problème a été résolu en n'observant pas les objets jusqu'à ce que le chargement de la vue soit terminé (auparavant, j'avais commencé à observer l'objet après l'attribution via l'accesseur)

TLDR: Vérifiez si vous essayez de recharger vos données à partir de quelque chose d'autre que le thread principal.

0
Jonathan Zhan