Falha de declaração em - [UITableView _endCellAnimationsWithContext:]

89

Esperançosamente, esta será uma solução rápida. Tenho tentado descobrir o erro que continuo recebendo. O erro está listado abaixo e o appdelagate está abaixo disso.

Qualquer ajuda é apreciada.

obrigado

2012-04-12 21: 11: 52.669 Chanda [75100: f803] --- Falha de declaração em -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52.671 Chanda [75100: f803] --- Encerrando aplicativo devido a exceção não capturada ' NSInternalInconsistencyException' , motivo: 'Atualização inválida: número inválido de linhas na seção 0. O número de linhas contidas em uma seção existente após a atualização (2) deve ser igual ao número de linhas contidas nessa seção antes da atualização (2), mais ou menos o número de linhas inseridas ou excluídas daquela seção (1 inserido, 0 excluído) e mais ou menos o número de linhas movidas para dentro ou para fora dessa seção (0 movido para dentro, 0 movido para fora). '

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize databaseName,databasePath; 

- (BOOL)application: (UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
    self.databaseName = @"Customers.db";

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDir = [documentPaths objectAtIndex:0];
    self.databasePath = [documentDir stringByAppendingPathComponent:self.databaseName];
    [self createAndCheckDatabase];

    return YES;
}

- (void)createAndCheckDatabase {
    BOOL success;

    NSFileManager *fileManager = [NSFileManager defaultManager];
    success = [fileManager fileExistsAtPath:databasePath];

    if (success) return; 

    NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseName];

    [fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}

@end
Scubadivingfool
fonte
3
Você deve mover esse código para classes e provavelmente executá-lo em um thread de segundo plano. De qualquer forma, esse erro normalmente surge quando você tenta remover linhas sem realmente diminuir o número de linhas conforme fornecido pela fonte de dados da exibição de tabela. Você está realmente removendo dados ao remover as linhas? Se você não está excluindo nenhuma linha, pode fornecer sua implementação de fonte de dados de exibição de tabela?
Constantino Tsarouhas

Respostas:

43

Não vejo razão para você nos mostrar esta parte do código. Seu erro deve estar conectado a esta parte do seu código, presumo

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

Provavelmente você está cometendo um erro em um desses métodos de fonte de dados. Atualmente é impossível dizer o que exatamente está errado, mas suponho que poderia ser algo como: Você está dizendo à visualização da tabela no numberOfRowsInSectionque gostaria de ter n linhas reservadas e configuradas e no cellForRowAtIndexPathentão você só lida com n - 1 linhas, por exemplo.

Lamento que esta resposta não possa ser tão precisa como deveria. Se você nos mostrar sua implementação de sua fonte de dados, será muito mais fácil saber o que está acontecendo.

PBX
fonte
26

Como Sun Tzu disse : é melhor vencer sem lutar . No meu caso, sempre que vejo esse tipo de mensagem de erro (ou seja, discrepância entre as linhas adicionadas, excluídas etc.) .. Eu nem mesmo depuro nada .. Eu simplesmente evito fazer aquela chamada extra em que recarrego as linhas etc. Isso é 99% de os casos em que esse erro acontece.

Este é um cenário comum em que esse bug acontece: eu tenho um UINavigationControllere ele tem um UITableView, quando clico em uma linha ele empurra um novo UITableViewe assim por diante. Este erro sempre acontece comigo quando eu coloco o último UITableviewe volto para o UITableViewanterior, neste ponto eu faço uma chamada desnecessária para a loadItfunção que basicamente insere as linhas e relaods o UITableView.

A razão pela qual isso acontece é porque eu coloco erroneamente minha função loadIt em viewDidAppear:animatedvez de viewDidLoad. viewDidAppear:animatedé chamado sempre que UITableViewé exibido, viewDidLoadé chamado apenas uma vez.

abbood
fonte
3
Obrigado, bem dito. Seu primeiro parágrafo me colocou no caminho certo para resolver um problema semelhante.
scrrr
2
é um prazer @scrrr :)
abbood
Isso mudou a maneira como eu olhava para ele - corrigiu o problema ao torná-lo irrelevante. Você é demais!
Charlie
Parabéns por viewDidAppear em vez de viewDidLoad. Esse era exatamente o meu problema e eu estava lidando com ele por semanas.
GrandSteph
1
Imprimi sua citação de Sun Tzu e colei-a no topo da tela. Obrigado pela citação e me ajudando a encontrar uma tonelada de código redundante :)
Adrian
24

Ao remover linhas, lembre-se de que ele também verifica as seções durante a atualização, em:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Se você quiser remover uma linha que é o último item em uma seção, você precisa remover a seção inteira (caso contrário, pode haver contagem de seção errada e gerar esta exceção).

Olof_t
fonte
1
Isso é ouro maciço! O prego acertou na cabeça! Exatamente meu problema.
phatmann
6

Não se esqueça de atualizar seu array que determina numberOfRowsInSection. Ele precisa ser atualizado antes de você animar e remover

Verificamos se o número de linhas na seção é 1 porque teremos que deletar toda a seção.

Corrija-me se alguém puder tornar esta resposta mais clara.

[self.tableView beginUpdates];
if ([tableView numberOfRowsInSection:indexPath.section] == 1) {

   [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else {

   [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
[self.tableView endUpdates];
love2script12
fonte
4

Coloquei cada elemento de seção em matrizes separadas. Em seguida, coloque-os em outra matriz (arrayWithArray). Minha solução aqui para este problema:

[quarantineMessages removeObject : message];
[_tableView beginUpdates];
if([[arrayWithArray objectAtIndex: indPath.section] count]  > 1)
{
    [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indPath] withRowAnimation:UITableViewRowAnimationBottom];
}
else
{
    [_tableView deleteSections:[NSIndexSet indexSetWithIndex:indPath.section]
              withRowAnimation:UITableViewRowAnimationFade];
}
[_tableView endUpdates];
Prumo
fonte
1
para mim foram as atualizações de início e fim que resolveram isso, obrigado!
Mark W
2
Eu não sabia disso sobre a seção ficar vazia e a necessidade de animá-la ao invés ... Droga! obrigado!
dvkch
1
Coloquei meu código para funcionar com muita ajuda dessa resposta. Poste abaixo.
love2script12
2

Eu tive o mesmo erro.

Eu estava usando as seguintes linhas

UINib *myCustomCellNib = [UINib nibWithNibName:@"CustomNib" bundle:nil];
[tableView registerNib:myCustomCellNib forCellReuseIdentifier:@"CustomNib"];

para registrar a ponta no método viewDidLoad, pois eu tinha uma ponta diferente que também estava associada à mesma classe. Portanto, a linha

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GBFBLoadingCell"];

estava retornando nil, a menos que eu registrasse a ponta no viewDidLoad.

Meu problema é que esqueci de definir o identificador no inspetor de atributos para o meu arquivo "CustomNib.xib" e "CustomNib ~ iphone.xib". (Ou mais precisamente, que esqueci de pressionar Enter depois de digitar o identificador no inspetor de atributos no XCode, de forma que o novo nome falhou ao salvar.)

Espero que isto ajude.

user1612868
fonte
2
Não creio que sua resposta tenha relação com a questão.
DawnSong
2

Se você estiver usando um NSFetchedResultsControllercomo eu e atualizando dados em um thread de segundo plano, não se esqueça de começar e terminar as atualizações no delegado:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}
mikeho
fonte
2

Tive o mesmo erro, que ao tentar [tableView reloadData]estava funcionando bem. O erro estava realmente na linha

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Quando tentei verificar os valores de indexPath, eles não estavam corretos, conforme necessário.

Consertei alterando os valores em indexPathsArray.

Espero que isto ajude .

user5553647
fonte
1

Pode ser um dos UITableViewDataSourcemétodos de protocolo

Para

- tableView:numberOfRowsInSection:

deve retornar um inteiro igual à soma ou resultado de

-insertRowsAtIndexPaths:withRowAnimation:e / ou -deleteRowsAtIndexPaths:withRowAnimation:

Para

- numberOfSectionsInTableView:

deve retornar um inteiro igual à soma ou resultado de

-insertRowsAtIndexPaths:withRowAnimation: e / ou -deleteSections:withRowAnimation:

Ted
fonte
0

Eu tive o mesmo problema com um banco de dados principal. Se estiver usando muitos FRC, você só precisa recarregar o tableview dentro de cada condição em numberOfSectionsInTableView.

Privatus Privatus
fonte
2
Eu também tenho esse problema com Core Data. Você pode elaborar sua receita.
Drux
0

Isso aconteceu comigo enquanto usava o Swift e um armazenamento de dados com suporte de FRC para gerenciar informações. Adicionar uma verificação simples à operação de exclusão para avaliar o indexPath.section atual me permitiu evitar uma chamada estranha. Acho que entendo por que esse problema ocorre ... Basicamente, eu carrego uma mensagem na linha superior sempre que meu conjunto de dados está vazio. Isso cria um problema fora por um, pois há uma linha falsa.

Minha Solução

... delete my entity, save the datastore and call reloadData on tableView
//next I add this simple check to avoid calling deleteRows when the system (wrongly) determines that there is no section.

       if indexPath.section > 0 {

        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .None)

            }
Tommie C.
fonte
0

Basta verificar se você chama [yourTableView reloadData]; depois de modificar a matriz de valores.

Evgeniy Kleban
fonte