Falha na asserção no dequeueReusableCellWithIdentifier: forIndexPath:

324

Então, eu estava criando um leitor de RSS para a minha escola e terminei o código. Fiz o teste e me deu esse erro. Aqui está o código ao qual está se referindo:

- (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];

    }

aqui está o erro na saída:

2012-10-04 20: 13: 05.356 Reader [4390: c07] * Falha de asserção em - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04 20: 13: 05.357 Reader [4390: c07] * Aplicativo de encerramento devido à exceção não capturada 'NSInternalInconsistencyException', motivo: 'não é possível retirar a fila de uma célula com identificador Cell - deve registrar uma ponta ou uma classe para o identificador ou conectar uma célula de protótipo em um storyboard ' * Primeiro pilha de chamadas lance: (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: terminado chamado lançando uma exceção

e aqui está o código que mostra na tela de erro:

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

por favor ajude!

Nick Scottman
fonte

Respostas:

488

Você está usando o dequeueReusableCellWithIdentifier:forIndexPath:método A documentação para esse método diz o seguinte:

Importante: Você deve registrar um arquivo de classe ou ponta usando o método registerNib:forCellReuseIdentifier:ou registerClass:forCellReuseIdentifier:antes de chamar este método.

Você não registrou uma ponta ou uma classe para o identificador de reutilização "Cell".

Olhando para o seu código, você espera que o método dequeue retorne nilse ele não tiver uma célula para fornecer. Você precisa usar o dequeueReusableCellWithIdentifier:para esse comportamento:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Observe que dequeueReusableCellWithIdentifier:e dequeueReusableCellWithIdentifier:forIndexPath:são métodos diferentes. Veja doc para o primeiro e o segundo .

Se você quiser entender por que deseja usar dequeueReusableCellWithIdentifier:forIndexPath:, consulte estas perguntas e respostas .

Rob Mayoff
fonte
166
AMD. Por que o modelo padrão do Xcode para um UITableViewController automaticamente fornece dequeueReusableCellWithIdentifier: forIndexPath :? Tão inútil.
spstanley
15
O dequeueReusableCellWithIdentifer:forIndexPath:(introduzido no iOS6) é uma melhoria agradável, pois você não precisa verificar se a célula é nula. ( UITableViewControllerFunciona de maneira semelhante a UICollectionView) Mas é irritante que essa alteração não seja comentada no modelo e que a mensagem de afirmação / falha não seja mais útil.
Jason Moore
2
No mínimo, você pensaria que o padrão seria UITableViewCell em vez de implodir. Baka.
precisa saber é o seguinte
13
A última linha desta resposta é de ouro: fui mordido mais de uma vez usando dequeueReusableCellWithIdentifier:forIndexPath:quando deveria estar usando dequeueReusableCellWithIdentifier:.
28413
Essa resposta é perfeita. Eu tenho uma pergunta: Eu tenho um tableViewController como meu controlador de exibição inicial. No didSelectRow ... estou empurrando outro tableViewController para a pilha de navegação. Como é que eu só tenho que registrar uma célula para o segundo tableViewController, não o inicial?
ArielSD 13/04
137

Acho que esse erro é sobre registrar sua ponta ou classe para o identificador.

Para que você possa manter o que está fazendo na função tableView: cellForRowAtIndexPath e apenas adicionar o código abaixo em seu viewDidLoad:

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

Funcionou para mim. Espero que ajude.


fonte
3
Um pequeno problema: verifique se o identificador de reutilização corresponde ao que você definiu nas configurações do Storyboard para a célula em questão.
precisa saber é o seguinte
Apenas para adicionar isso a um caso de uso um pouco diferente, eu estava selecionando novamente uma linha na visualização Mestre do meu SplitViewController. Essa lógica de nova seleção de linha estava na viewDidLoade movendo essa lógica para viewDidAppearcorrigi-la.
Craig Conover
Ele não pôde entrar na célula == nil; portanto, minha célula do tableview sempre é nula.
Solid Soft
3
swift 3.0: self.tableView.register (UITableViewCell.classForCoder (), forCellReuseIdentifier: "Cell");
NorbDEV 26/09/16
68

Embora essa pergunta seja bastante antiga, há outra possibilidade: se você estiver usando Storyboards, basta definir o CellIdentifier no Storyboard.

Portanto, se o seu CellIdentifier for "Cell", basta definir a propriedade "Identifier": insira a descrição da imagem aqui

Certifique-se de limpar sua compilação depois de fazer isso. O XCode às vezes tem alguns problemas com as atualizações do Storyboard

Sebastian Borggrewe
fonte
3
você é incrível, a limpeza faz muito !! : D
Sandy
2
Nota - se você usar um identificador diferente de "Cell", também precisará alterar o método cellForRowAtIndexPath para usar esse identificador na seguinte linha: static NSString * CellIdentifier = @ "MyCellIdentifier";
Gamozzii #
5
Um complemento importante para isso: A vista da tabela deve ter o seu "conteúdo" conjunto de atributos para "Protótipos dinâmico", e não "Células estáticos"
Ted Avery
Esta resposta precisa subir mais. Muito útil
Sukitha Udugamasooriya
A limpeza da construção era essencial após a atualização da Identifierpropriedade. Obrigado!
Crashalot
59

eu tive o mesmo problema ao substituir por

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

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

    }

resolvido

iMeMyself
fonte
Obrigado. Isso me salvou de dor de cabeça. =)
Robert
3
dica: se você usar um - (id) dequeueReusableCellWithIdentifier: forIndexPath:, não precisará verificar se a célula é nula. (IOS6>)
seufagner
apenas me salvou de dor de cabeça. =)
Abo3atef 23/01
26

O problema é mais provável porque você configura o UITableViewCellstoryboard personalizado , mas não usa o storyboard para instanciar o UITableViewControllerque usa isso UITableViewCell. Por exemplo, no MainStoryboard, você tem uma UITableViewControllersubclasse chamada MyTableViewControllere uma dinâmica personalizada UITableViewCellchamada MyTableViewCellcom o identificador "MyCell".

Se você criar seu costume UITableViewControllerassim:

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

Ele não registrará automaticamente sua célula de tableview personalizada para você. Você precisa registrá-lo manualmente.

Mas se você usar o storyboard para instanciar MyTableViewController, assim:

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

Coisa boa acontece! UITableViewControllerregistrará automaticamente sua célula de tableview personalizada que você definir no storyboard para você.

No método delegado "cellForRowAtIndexPath", você pode criar sua célula de exibição de tabela assim:

- (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 criará automaticamente uma nova célula para você, se não houver uma célula reutilizável disponível na fila de reciclagem.

Então você está pronto!

James Wang
fonte
A dica que usar instantiateViewControllerWithIdentifierpara iniciar meu viewController salvou meu dia!
Lei Zhang
salvou meu dia: células protótipos estavam no VC vizinha com uma mesa
Anton Tropashko
Esta é a causa razoável no meu caso.
Nora Alnashwan
19

Vou acrescentar que o Xcode 4.5 inclui o novo dequeueReusableCellWithIdentifier:forIndexPath:
em seu código de modelo padrão - uma possibilidade potencial para desenvolvedores que esperam o dequeueReusableCellWithIdentifier:método mais antigo .

Brian Shriver
fonte
Me picou! Agora eu vou saber melhor. ;)
spstanley
18

No seu storyboard, você deve definir o 'Identificador' da sua célula protótipo para ser o mesmo que o seu CellReuseIdentifier "Cell". Então você não receberá essa mensagem ou precisará chamar essa função registerClass:.

Steven
fonte
2
Peguei vocês! Onde está o botão '100 upvotes'. Esta é a solução real.
precisa saber é o seguinte
Você pensaria que adicionar um novo tableView em um storyboard fornecerá um identificador padrão - 'Cell' para você. É tão facilmente esquecido, especialmente se você estiver usando o chamado 'código livre' em tableView: cellForRowAtIndexPath!
ushika
18

Solução Swift 2.0:

Você precisa acessar o Inspetor de Atributos e adicionar um nome para o identificador de suas células:

insira a descrição da imagem aqui

Então você precisa fazer o seu identificador corresponder à sua desenfileiramento da seguinte forma:

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

alternativamente

Se você estiver trabalhando com uma ponta, talvez seja necessário registrar sua classe em seu 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    
}

A referência de classe UITableView da Apple diz:

Antes de remover a fila de qualquer célula, chame esse método ou o método registerNib: forCellReuseIdentifier: para informar à visualização da tabela como criar novas células. Se uma célula do tipo especificado não estiver atualmente em uma fila de reutilização, a visualização da tabela utilizará as informações fornecidas para criar um novo objeto de célula automaticamente.

Se você registrou anteriormente um arquivo de classe ou ponta com o mesmo identificador de reutilização, a classe especificada no parâmetro cellClass substitui a entrada antiga. Você pode especificar nil para cellClass se desejar cancelar o registro da classe do identificador de reutilização especificado.

Aqui está o código da estrutura do 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
fonte
Eu não entendo de onde SwitchCell.selfvem?
Gert Cuykens
@GertCuykens SwitchCell é meu UITableViewCell personalizado
Dan Beaulieu
1
Agora estou longe do meu Mac, mas definitivamente posso atualizá-lo quando chegar em casa.
Dan Beaulieu
1
Substituí-lo por UITableViewCell.selfparece funcionar para mim. Talvez adicionar uma nota na resposta
Gert Cuykens
@GertCuykens obrigado por apontar isso, eu mudei SwitchCell.self para UITableViewCell.self
Dan Beaulieu
3

Se você usar células estáticas personalizadas, apenas comente este método:

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

e forneça às células um identificador no "Attributes Inspector" no storyboard.

Francisco Gutiérrez
fonte
3

Dou-lhe a resposta no Objetivo C e no Swift. Antes disso, quero dizer

Se usarmos o dequeueReusableCellWithIdentifier:forIndexPath:, devemos registrar um arquivo de classe ou ponta usando o método registerNib: forCellReuseIdentifier: ou registerClass: forCellReuseIdentifier: antes de chamar esse método, como a Apple Documnetation Says

Então nós adicionamos registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:

Depois que registramos uma classe para o identificador especificado e uma nova célula deve ser criada, esse método inicializa a célula chamando seu método initWithStyle: reuseIdentifier:. Para células baseadas em ponta, esse método carrega o objeto de célula do arquivo de ponta fornecido. Se uma célula existente estava disponível para reutilização, esse método chama o método prepareForReuse da célula.

no método viewDidLoad, devemos registrar a célula

Objetivo C

OPÇÃO 1:

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

OPÇÃO 2:

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

no código acima, nibWithNibName:@"CustomCell"forneça seu nome de ponta em vez do meu nome de ponta CustomCell

RÁPIDO

OPÇÃO 1:

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

OPÇÃO 2:

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

no código acima, nibName:"NameInput"dê seu nome de ponta

user3182143
fonte
3

Trabalhando com o 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
fonte
2

Passei horas na noite passada tentando descobrir por que minha tabela gerada programaticamente caiu em [myTable setDataSource: self]; Foi bom comentar e exibir uma tabela vazia, mas travou toda vez que tentei acessar a fonte de dados;

Eu tinha a delegação configurada no arquivo h: @interface myViewController: UIViewController

Eu tinha o código fonte de dados na minha implementação e ainda o BOOM !, sempre travava! OBRIGADO por "xxd" (nº 9): adicionar essa linha de código resolveu isso para mim! Na verdade, estou lançando uma tabela a partir de um botão IBAction, então aqui está o meu código completo:

    - (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;
   }

A propósito: o botão deve estar vinculado como um IBAction e como um IBOutlet se você deseja ancorar o popover nele.

UIPopoverController * popoverController3 é declarado no arquivo H diretamente após @interface entre {}

Simone
fonte
2

FWIW, recebi esse mesmo erro quando esqueci de definir o identificador de célula no storyboard. Se esse for o seu problema, no storyboard, clique na célula da exibição de tabela e defina o identificador da célula no editor de atributos. Verifique se o identificador de célula que você define aqui é o mesmo que

static NSString *CellIdentifier = @"YourCellIdenifier";
honkskillet
fonte
2

Eu tive o mesmo problema, estava tendo o mesmo erro e, para mim, funcionou assim:

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

Talvez seja útil para outra pessoa.

CarmenA
fonte
2

Configurei tudo corretamente no Storyboard e fiz uma compilação limpa, mas continuei recebendo o erro " deve registrar uma ponta ou uma classe para o identificador ou conectar uma célula protótipo em um storyboard "

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

Corrigido o erro, mas ainda estou perdido. Não estou usando uma 'célula personalizada', apenas uma exibição com uma exibição de tabela incorporada. Declarei o viewcontroller como delegado e fonte de dados e verifiquei se o identificador de célula corresponde no arquivo. O que está acontecendo aqui?

FrostyL
fonte
1

Isso pode parecer estúpido para algumas pessoas, mas me pegou. Eu estava recebendo esse erro e o problema para mim era que estava tentando usar células estáticas, mas adicionava mais coisas dinamicamente. Se você está chamando esse método, suas células precisam ser protótipos dinâmicos. Selecione a célula no storyboard e, no inspetor Atributos, a primeira coisa que diz 'Conteúdo' e você deve selecionar protótipos dinâmicos não estáticos.

Chase Roberts
fonte
OBRIGADO! Este foi exatamente o meu problema.
Isaiah Turner
1

Apenas um complemento das respostas: pode haver um tempo em que você ajusta tudo, mas acidentalmente pode adicionar outras UIs em você .xib, como UIButton: insira a descrição da imagem aqui Apenas exclua a UI extra, ela funciona.

DrustZ
fonte
1

Certifique-se de que o CellIdentifier == identificador da célula em um storyboard, os dois nomes sejam iguais. Espero que isso funcione para você

Ankit garg
fonte
0

No meu caso, o acidente aconteceu quando ligueideselectRowAtIndexPath:

A linha era [tableView deselectRowAtIndexPath:indexPath animated:YES];

Mudando para [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; FIXO MEU PROBLEMA!

Espero que isso ajude alguém

Offek
fonte
0

Em Swift, esse problema pode ser resolvido adicionando o código a seguir no seu

viewDidLoad

método.

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

Deparamos com esse erro O identificador de reutilização da célula bc estava errado - um erro de novato, mas acontece: 1. Faz com que o identificador de reutilização da célula SURE não tenha erros de ortografia ou letras ausentes. 2. Na mesma linha, não esqueça a contagem de letras maiúsculas. 3. Zeros não são "O" s (Ohs)

John Pitts
fonte