Échec de l'assertion dans dequeueReusableCellWithIdentifier: forIndexPath:

324

Donc je faisais un lecteur rss pour mon école et finissais le code. J'ai exécuté le test et cela m'a donné cette erreur. Voici le code auquel il fait référence:

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = 
     [tableView dequeueReusableCellWithIdentifier:CellIdentifier 
                                     forIndexPath:indexPath];
    if (cell == nil) {

        cell = 
         [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle  
                                reuseIdentifier:CellIdentifier];

    }

voici l'erreur dans la sortie:

2012-10-04 20: 13: 05.356 Reader [4390: c07] * Échec d'assertion dans - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04 20:: 13: 05.357 Reader [4390: c07] * Arrêt de l'application en raison d'une exception non interceptée 'NSInternalInconsistencyException', raison: 'impossible de retirer une cellule avec l'identifiant Cell - doit enregistrer une plume ou une classe pour l'identifiant ou connecter une cellule prototype dans un storyboard ' * pile premier appel de lancer: (0x1c91012 0x10cee7e 0x1c90e78 0xb64f35 0xc7d14 0x39ff 0xd0f4b 0xd101f 0xb980b 0xca19b 0x6692d 0x10e26b0 0x228dfc0 0x228233c 0x228deaf 0x1058cd 0x4e1a6 0x4ccbf 0x4cbd9 0x4be34 0x4bc6e 0x4ca29 0x4f922 0xf9fec 0x46bc4 0x47311 0x2cf3 0x137b7 0x13da7 0x14fab 0x26315 0x2724b 0x18cf8 0x1becdf9 0x1becad0 0x1c06bf5 0x1c06962 0x1c37bb6 0x1c36f44 0x1c36e1b 0x147da 0x1665c 0x2a02 0x2935 ) libc ++ abi.dylib: terminate appelé levant une exception

et voici le code qu'il affiche dans l'écran d'erreur:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

s'il vous plaît, aidez!

Nick Scottman
la source

Réponses:

488

Vous utilisez la dequeueReusableCellWithIdentifier:forIndexPath:méthode. La documentation de cette méthode dit ceci:

Important: vous devez enregistrer une classe ou un fichier nib à l'aide de la méthode registerNib:forCellReuseIdentifier:ou registerClass:forCellReuseIdentifier:avant d'appeler cette méthode.

Vous n'avez pas enregistré de nib ou de classe pour l'identifiant de réutilisation "Cell".

En regardant votre code, vous semblez vous attendre à ce que la méthode de dequeue revienne nilsi elle n'a pas de cellule à vous donner. Vous devez utiliser le dequeueReusableCellWithIdentifier:pour ce comportement:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Notez cela dequeueReusableCellWithIdentifier:et ce dequeueReusableCellWithIdentifier:forIndexPath:sont des méthodes différentes. Voir le doc pour le premier et le dernier .

Si vous voulez comprendre pourquoi vous voudriez jamais l'utiliser dequeueReusableCellWithIdentifier:forIndexPath:, consultez cette Q&R .

rob mayoff
la source
166
OMG. Pourquoi le modèle par défaut de Xcode pour un UITableViewController vous donne-t-il automatiquement dequeueReusableCellWithIdentifier: forIndexPath :? Si inutile.
spstanley
15
Le dequeueReusableCellWithIdentifer:forIndexPath:(introduit dans iOS6) est une belle amélioration, car vous n'avez pas besoin de vérifier si la cellule est nulle. (Fonctionne donc de manière UITableViewControllersimilaire à UICollectionView) Mais oui, ennuyeux que cette modification ne soit pas un commentaire dans le modèle et que le message d'assertion / crash ne soit pas plus utile.
Jason Moore
2
À tout le moins, vous penseriez que ce serait par défaut UITableViewCell au lieu d'imploser. Baka.
BadPirate
13
La dernière ligne de cette réponse est dorée: j'ai été mordu plus d'une fois en utilisant dequeueReusableCellWithIdentifier:forIndexPath:quand j'aurais dû utiliser dequeueReusableCellWithIdentifier:.
ele
Cette réponse est parfaite. J'ai une question: j'ai un tableViewController comme contrôleur de vue initial. À didSelectRow ... J'insère une autre tableViewController sur la pile de navigation. Comment se fait-il que je n'ai qu'à enregistrer une cellule pour le deuxième tableViewController, pas l'initiale?
ArielSD
137

Je pense que cette erreur concerne l'enregistrement de votre nib ou classe pour l'identifiant.

Afin que vous puissiez conserver ce que vous faites dans votre fonction tableView: cellForRowAtIndexPath et simplement ajouter du code ci-dessous dans votre viewDidLoad:

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

Ça a marché pour moi. J'espère que cela peut aider.


la source
3
Un petit problème avec cela - assurez-vous que l'identifiant de réutilisation correspond à ce que vous avez configuré dans vos paramètres de Storyboard pour la cellule en question.
James Boutcher
Pour ajouter à cela dans un cas d'utilisation légèrement différent, je resélectionnais une ligne dans la vue principale de mon SplitViewController. Cette logique de resélection de ligne se trouvait dans le viewDidLoadet le déplacement de cette logique pour la viewDidAppearcorriger.
Craig Conover
Il n'a pas pu entrer dans la cellule == nil, donc ma cellule tableview toujours nil.
Solid Soft
3
swift 3.0: self.tableView.register (UITableViewCell.classForCoder (), forCellReuseIdentifier: "Cell");
norbDEV
68

Bien que cette question soit assez ancienne, il existe une autre possibilité: si vous utilisez des storyboards, il vous suffit de définir le CellIdentifier dans le storyboard.

Donc, si votre CellIdentifier est "Cell", définissez simplement la propriété "Identifier": entrez la description de l'image ici

Assurez-vous de nettoyer votre build après l'avoir fait. XCode a parfois quelques problèmes avec les mises à jour du Storyboard

Sebastian Borggrewe
la source
3
vous êtes génial, le nettoyage fait beaucoup !! : D
Sandy
2
Remarque - si vous utilisez un identifiant autre que "Cell", vous devrez également modifier votre méthode cellForRowAtIndexPath pour utiliser cet identificateur sur la ligne suivante: static NSString * CellIdentifier = @ "MyCellIdentifier";
gamozzii
5
Un ajout important à cela: la vue de la table doit avoir son attribut "Content" défini sur "Dynamic Prototypes", PAS "Static Cells"
Ted Avery
Cette réponse doit venir plus haut. Très utile
Sukitha Udugamasooriya
Le nettoyage était essentiel après la mise à jour de la Identifierpropriété. Merci!
Crashalot
59

j'ai eu le même problème en remplaçant par

static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

   if (cell==nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

    }

résolu

je moi moi-même
la source
Je vous remercie. Cela m'a juste sauvé un mal de tête. =)
Robert
3
astuce: si vous utilisez un - (id) dequeueReusableCellWithIdentifier: forIndexPath:, vous n'avez pas besoin de vérifier si la cellule est nulle. (IOS6>)
seufagner
vient de me sauver un mal de tête. =)
Abo3atef
26

Le problème est probablement dû au fait que vous configurez la personnalisation UITableViewCelldans le storyboard mais que vous n'utilisez pas le storyboard pour instancier votre UITableViewControllerqui l'utilise UITableViewCell. Par exemple, dans MainStoryboard, vous avez une UITableViewControllersous - classe appelée MyTableViewControlleret une dynamique personnalisée UITableViewCellappelée MyTableViewCellavec l'identifiant id "MyCell".

Si vous créez votre personnalisé UITableViewControllercomme ceci:

 MyTableViewController *myTableViewController = [[MyTableViewController alloc] init];

Il n'enregistrera pas automatiquement votre cellule de visualisation personnalisée pour vous. Vous devez l'enregistrer manuellement.

Mais si vous utilisez le storyboard pour instancier MyTableViewController, comme ceci:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MyTableViewController *myTableViewController = [storyboard  instantiateViewControllerWithIdentifier:@"MyTableViewController"];

Une bonne chose arrive! UITableViewControllerenregistrera automatiquement votre cellule de vue de table personnalisée que vous définissez dans le storyboard pour vous.

Dans votre méthode déléguée "cellForRowAtIndexPath", vous pouvez créer votre cellule de vue de table comme ceci:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

//Configure your cell here ...

return cell;
}

dequeueReusableCellWithIdentifier créera automatiquement une nouvelle cellule pour vous s'il n'y a pas de cellule réutilisable disponible dans la file d'attente de recyclage.

Alors vous avez terminé!

James Wang
la source
L'astuce que l'utilisation instantiateViewControllerWithIdentifierpour lancer mon viewController m'a sauvé la journée!
Lei Zhang
sauvé ma journée: les cellules prototypes étaient dans le VC voisin avec une table
Anton Tropashko
C'est la cause raisonnable dans mon cas.
Nora Alnashwan
19

J'ajouterai simplement que Xcode 4.5 inclut le nouveau dequeueReusableCellWithIdentifier:forIndexPath:
dans son code de modèle par défaut - un piège potentiel pour les développeurs qui attendent l'ancienne dequeueReusableCellWithIdentifier:méthode.

Brian Shriver
la source
M'a piqué! Maintenant je saurai mieux. ;)
spstanley
18

Dans votre storyboard, vous devez définir «l'identifiant» de votre cellule prototype pour qu'il soit le même que votre «cellule» CellReuseIdentifier. Ensuite, vous n'obtiendrez pas ce message ou vous n'aurez pas besoin d'appeler cette fonction registerClass :.

Steven
la source
2
Je t'ai eu! Où est le bouton «100 votes positifs». Telle est la vraie solution.
Jojo.Lechelt
Vous pensez que l'ajout d'une nouvelle tableView dans un storyboard vous fournira un identifiant par défaut - «Cellule». Il est si facilement ignoré, surtout si vous utilisez le soi-disant «code libre» dans tableView: cellForRowAtIndexPath!
ushika
18

Solution Swift 2.0:

Vous devez aller dans votre inspecteur d'attributs et ajouter un nom pour votre identifiant de cellules:

entrez la description de l'image ici

Ensuite, vous devez faire correspondre votre identifiant avec votre file d'attente comme ceci:

let cell2 = tableView.dequeueReusableCellWithIdentifier("ButtonCell", forIndexPath: indexPath) as! ButtonCell

Alternativement

Si vous travaillez avec une pointe, vous devrez peut-être enregistrer votre classe dans votre cellForRowAtIndexPath:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {       

    tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwitchCell")

    // included for context            
    let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath:indexPath) as! SwitchCell

    //... continue    
}

La référence de classe UITableView d'Apples indique:

Avant de retirer des cellules de la file d'attente, appelez cette méthode ou la méthode registerNib: forCellReuseIdentifier: pour indiquer à la table comment créer de nouvelles cellules. Si une cellule du type spécifié n'est pas actuellement dans une file d'attente de réutilisation, la vue de table utilise les informations fournies pour créer automatiquement un nouvel objet cellule.

Si vous avez précédemment enregistré une classe ou un fichier nib avec le même identifiant de réutilisation, la classe que vous spécifiez dans le paramètre cellClass remplace l'ancienne entrée. Vous pouvez spécifier nil pour cellClass si vous souhaitez désinscrire la classe de l'identifiant de réutilisation spécifié.

Voici le code du framework Apples Swift 2.0:

// Beginning in iOS 6, clients can register a nib or class for each cell.
// If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
// Instances returned from the new dequeue method will also be properly sized when they are returned.

@available(iOS 5.0, *)
func registerNib(nib: UINib?, forCellReuseIdentifier identifier: String)

@available(iOS 6.0, *)
func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
Dan Beaulieu
la source
Je ne comprends pas d'où SwitchCell.selfvient?
Gert Cuykens
@GertCuykens SwitchCell est mon UITableViewCell personnalisé
Dan Beaulieu
1
Je suis loin de mon Mac en ce moment, mais je peux certainement le mettre à jour quand je rentrerai.
Dan Beaulieu
1
Le remplacer par UITableViewCell.selfsemble fonctionner pour moi. Peut-être ajouter une note dans la réponse
Gert Cuykens
@GertCuykens merci de l'avoir signalé, j'ai changé SwitchCell.self pour UITableViewCell.self
Dan Beaulieu
3

Si vous utilisez des cellules statiques personnalisées, commentez simplement cette méthode:

//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//    static NSString *CellIdentifier = @"notificationCell";
//    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//    return cell;
//}

et attribuez aux cellules un identifiant dans "Inspecteur des attributs" dans le storyboard.

Francisco Gutiérrez
la source
3

Je vous donne la réponse à la fois dans l'objectif C et Swift. Avant cela, je veux dire

Si nous utilisons la dequeueReusableCellWithIdentifier:forIndexPath:, nous devons enregistrer une classe ou un fichier nib à l'aide de la méthode registerNib: forCellReuseIdentifier: ou registerClass: forCellReuseIdentifier: avant d'appeler cette méthode comme le dit Apple Documnetation

Nous ajoutons donc registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:

Une fois que nous avons enregistré une classe pour l'identifiant spécifié et qu'une nouvelle cellule doit être créée, cette méthode initialise la cellule en appelant sa méthode initWithStyle: reuseIdentifier:. Pour les cellules basées sur nib, cette méthode charge l'objet cellule à partir du fichier nib fourni. Si une cellule existante était disponible pour une réutilisation, cette méthode appelle à la place la méthode prepareForReuse de la cellule.

dans la méthode viewDidLoad, nous devons enregistrer la cellule

Objectif c

OPTION 1:

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];

OPTION 2:

[self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] forCellReuseIdentifier:@"cell"];

dans le code ci-dessus, nibWithNibName:@"CustomCell"donnez votre nom de plume au lieu de mon nom de plume CustomCell

RAPIDE

OPTION 1:

tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

OPTION 2:

tableView.registerNib(UINib(nibName: "NameInput", bundle: nil), forCellReuseIdentifier: "Cell") 

dans le code ci-dessus, nibName:"NameInput"donnez votre nom de plume

user3182143
la source
3

Travailler avec Swift 3.0:

override func viewDidLoad() {
super.viewDidLoad()

self.myList.register(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
}



public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myList.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! MyTableViewCell

return cell
}
norbDEV
la source
2

J'ai passé des heures la nuit dernière à comprendre pourquoi ma table générée par programme s'est écrasée sur [myTable setDataSource: self]; C'était OK de commenter et de faire apparaître une table vide, mais ça plantait à chaque fois que j'essayais d'atteindre la source de données;

J'ai fait configurer la délégation dans le fichier h: @interface myViewController: UIViewController

J'avais le code source de données dans mon implémentation et toujours BOOM !, plantez à chaque fois! MERCI à "xxd" (n ° 9): l'ajout de cette ligne de code l'a résolu pour moi! En fait, je lance une table à partir d'un bouton IBAction, voici donc mon code complet:

    - (IBAction)tapButton:(id)sender {

    UIViewController* popoverContent = [[UIViewController alloc]init];

    UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
    popoverView.backgroundColor = [UIColor greenColor];
    popoverContent.view = popoverView;

    //Add the table
    UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)         style:UITableViewStylePlain];

   // NEXT THE LINE THAT SAVED MY SANITY Without it the program built OK, but crashed when      tapping the button!

    [table registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    table.delegate=self;
    [table setDataSource:self];
    [popoverView addSubview:table];
    popoverContent.contentSizeForViewInPopover =
    CGSizeMake(200, 300);

    //create a popover controller
    popoverController3 = [[UIPopoverController alloc]
                          initWithContentViewController:popoverContent];
    CGRect popRect = CGRectMake(self.tapButton.frame.origin.x,
                                self.tapButton.frame.origin.y,
                                self.tapButton.frame.size.width,
                                self.tapButton.frame.size.height);


    [popoverController3 presentPopoverFromRect:popRect inView:self.view   permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];



   }


   #Table view data source in same m file

   - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
   {
    NSLog(@"Sections in table");
    // Return the number of sections.
    return 1;
   }

   - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
  {
    NSLog(@"Rows in table");

    // Return the number of rows in the section.
    return myArray.count;
   }

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath    *)indexPath
    {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NSString *myValue;

    //This is just some test array I created:
    myValue=[myArray objectAtIndex:indexPath.row];

    cell.textLabel.text=myValue;
    UIFont *myFont = [ UIFont fontWithName: @"Arial" size: 12.0 ];
    cell.textLabel.font  = myFont;

    return cell;
   }

Soit dit en passant: le bouton doit être lié en tant qu'IBAction et en tant qu'IBOutlet si vous souhaitez y ancrer le popover.

UIPopoverController * popoverController3 est déclaré dans le fichier H directement après @interface entre {}

Simone
la source
2

FWIW, j'ai eu cette même erreur quand j'ai oublié de définir l'identifiant de cellule dans le storyboard. Si tel est votre problème, cliquez dans la table de montage séquentiel sur la cellule du tableau et définissez l'identifiant de la cellule dans l'éditeur d'attributs. Assurez-vous que l'identifiant de cellule que vous définissez ici est le même que

static NSString *CellIdentifier = @"YourCellIdenifier";
honkskillet
la source
2

J'ai eu le même problème, j'ai eu la même erreur et pour moi, cela a fonctionné comme ceci:

[self.tableView registerNib:[UINib nibWithNibName:CELL_NIB_HERE bundle: nil] forCellReuseIdentifier:CELL_IDENTIFIER_HERE];

Peut-être que ce sera utile pour quelqu'un d'autre.

CarmenA
la source
2

J'ai tout installé correctement dans le Storyboard et fait une construction propre mais j'ai continué à obtenir l'erreur " doit enregistrer une nib ou une classe pour l'identifiant ou connecter une cellule prototype dans un storyboard "

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

Correction de l'erreur mais je suis toujours perdu. Je n'utilise pas de «cellule personnalisée», juste une vue avec une vue de table intégrée. J'ai déclaré le viewcontroller comme délégué et source de données et je me suis assuré que l'identifiant de cellule correspond dans le fichier. que se passe t-il ici?

FrostyL
la source
1

Cela peut sembler stupide à certaines personnes, mais cela m'a attiré. J'obtenais cette erreur et le problème pour moi était que j'essayais d'utiliser des cellules statiques mais ensuite d'ajouter dynamiquement plus de choses. Si vous appelez cette méthode, vos cellules doivent être des prototypes dynamiques. Sélectionnez la cellule dans le storyboard et sous l'inspecteur d'attributs, la toute première chose dit «Contenu» et vous devez sélectionner des prototypes dynamiques non statiques.

Chase Roberts
la source
MERCI! C'était exactement mon problème.
Isaiah Turner
1

Juste un complément des réponses: Il peut y avoir un moment où vous définissez tout correctement, mais vous pouvez accidentellement ajouter d'autres interfaces utilisateur en vous .xib, comme un UIButton: entrez la description de l'image ici Supprimez simplement l'interface utilisateur supplémentaire, cela fonctionne.

DrustZ
la source
1

Assurez-vous que l'identifiant CellIdentifier == de la cellule dans un storyboard, les deux noms sont identiques. J'espère que cela fonctionne pour vous

Garg Ankit
la source
0

Dans mon cas, le crash s'est produit lorsque j'ai appelédeselectRowAtIndexPath:

La ligne était [tableView deselectRowAtIndexPath:indexPath animated:YES];

Le changer en [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; FIXE MON PROBLÈME!

J'espère que cela aide n'importe qui

Offek
la source
0

Dans Swift, ce problème peut être résolu en ajoutant le code suivant dans votre

viewDidLoad

méthode.

tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "your_reuse_identifier")
arango_86
la source
-1

Ran dans cette erreur bc identifiant de réutilisation de cellule était erroné - une erreur de débutant mais cela arrive: 1. S'assure que l'identifiant de réutilisation de cellule n'a pas de fautes d'orthographe ou de lettres manquantes. 2. Dans le même ordre d'idées, n'oubliez pas les chiffres de capitalisation. 3. Les zéros ne sont pas des "O" (Ohs)

John Pitts
la source