Error de afirmación en - [UITableView _endCellAnimationsWithContext:]

89

Con suerte, esto será una solución rápida. He estado tratando de averiguar el error que sigo recibiendo. El error se enumera a continuación y la appdelagate está debajo.

Se agradece cualquier ayuda.

Gracias

2012-04-12 21: 11: 52.669 Chanda [75100: f803] --- Error de afirmación en -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52.671 Chanda [75100: f803] --- Finalizando la aplicación debido a una excepción no detectada ' NSInternalInconsistencyException' , motivo: 'Actualización no válida: número de filas no válido en la sección 0. El número de filas contenidas en una sección existente después de la actualización (2) debe ser igual al número de filas contenidas en esa sección antes de la actualización (2), más o menos el número de filas insertadas o eliminadas de esa sección (1 insertada, 0 eliminada) y más o menos el número de filas movidas dentro o fuera de esa sección (0 movidas hacia adentro, 0 movidas hacia afuera). '

#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
fuente
3
Debería mover ese código a las clases y probablemente ejecutarlo en un hilo de fondo. De todos modos, este error suele surgir cuando intenta eliminar filas sin disminuir realmente el número de filas que proporciona la fuente de datos de la vista de tabla. ¿Realmente está eliminando datos cuando elimina las filas? Si no está eliminando ninguna fila, ¿puede proporcionar la implementación de la fuente de datos de la vista de tabla?
Constantino Tsarouhas

Respuestas:

43

No veo la razón para que nos muestre esta parte del código. Su error debe estar conectado a esta parte en su código, supongo

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

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

Probablemente esté cometiendo un error en uno de estos métodos de fuente de datos. Actualmente es imposible decir qué es exactamente lo que está mal, pero supongo que podría ser algo como: le está diciendo a la vista de tabla en el numberOfRowsInSectionque le gustaría tener n filas reservadas y configuradas y en el cellForRowAtIndexPathque solo maneja n - 1 filas, por ejemplo.

Lamento que esta respuesta no pueda ser tan precisa como debería ser. Si nos muestra la implementación de su fuente de datos, sería mucho más fácil saber qué está pasando.

pbx
fuente
26

Como dijo Sun Tzu : es mejor ganar sin pelear . En mi caso, cada vez que veo este tipo de mensaje de error (es decir, discrepancia entre las filas agregadas eliminadas, etc.). Ni siquiera depuro nada ... Simplemente evito hacer esa llamada adicional donde recargo las filas, etc. eso es el 99% de los casos en los que ocurre este error.

Este es un escenario común en el que ocurre este error: tengo un UINavigationControllery tiene un UITableView, cuando hago clic en una fila, empuja una nueva UITableViewy así sucesivamente. Este error siempre me sucede cuando abro el último UITableviewy vuelvo al UITableViewanterior, en este punto hago una llamada innecesaria a la loadItfunción que básicamente inserta las filas y reenvía el archivo UITableView.

La razón por la que esto sucede es porque coloco erróneamente mi función loadIt en en viewDidAppear:animatedlugar de viewDidLoad. viewDidAppear:animatedse llama cada vez que UITableViewse muestra, viewDidLoadsolo se llama una vez.

abbood
fuente
3
Gracias, bien dicho. Tu primer párrafo me puso en el camino correcto para resolver un problema similar.
scrrr
2
es un placer @scrrr :)
abbood
Esto cambió mi forma de verlo: solucionó el problema haciéndolo irrelevante. ¡Tú Molas!
Charlie
Felicitaciones a viewDidAppear en lugar de viewDidLoad. Ese era exactamente mi problema y lo estuve lidiando durante semanas.
GrandSteph
1
Imprimí tu cita de Sun Tzu y la pegué en la parte superior de mi pantalla. Gracias por la cita y por ayudarme a encontrar un montón de código redundante :)
Adrian
24

Al eliminar filas, recuerde que también verifica las secciones al actualizar, en:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Si desea eliminar una fila que es el último elemento de una sección, debe eliminar toda la sección en su lugar (de lo contrario, es posible que el recuento de secciones sea incorrecto y arroje esta excepción).

Olof_t
fuente
1
¡Esto es oro macizo! ¡Clavo golpeado en la cabeza! Exactamente mi problema.
phatmann
6

No olvide actualizar su matriz que determina numberOfRowsInSection. Debe actualizarse antes de animar y eliminar

Comprobamos si el número de filas en la sección es 1 porque tendremos que eliminar toda la sección.

Corríjame si alguien puede aclarar esta respuesta.

[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
fuente
4

Pongo los elementos de cada sección en matrices separadas. Luego, colóquelos en otra matriz (arrayWithArray). Mi solución aquí 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];
Beto
fuente
1
para mí fueron las actualizaciones iniciales y finales las que lo resolvieron, ¡gracias!
Mark W
2
No sabía que la sección se vaciaría y la necesidad de animarla en su lugar ... ¡Maldita sea! ¡Gracias!
dvkch
1
Conseguí que mi código funcionara con mucha ayuda de esta respuesta. Publicándolo a continuación.
love2script12
2

Yo tenía el mismo error.

Estaba usando las siguientes líneas

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

para registrar la punta en el método viewDidLoad, ya que tenía una punta diferente que también estaba asociada con la misma clase. Por lo tanto, la línea

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

devolvía nulo a menos que registrara la punta en viewDidLoad.

Mi problema fue que olvidé establecer el identificador en el inspector de atributos para mi archivo "CustomNib.xib" y "CustomNib ~ iphone.xib". (O más precisamente, que olvidé presionar enter después de escribir el identificador en el inspector de atributos en XCode, por lo que el nuevo nombre no se pudo guardar).

Espero que esto ayude.

user1612868
fuente
2
NO creo que tu respuesta tenga relación con el tema.
DawnSong
2

Si está usando un NSFetchedResultsControllerme gusta y está actualizando datos en un hilo en segundo plano, no olvide comenzar y finalizar las actualizaciones en el delegado:

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

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

Tuve el mismo error, que al intentarlo [tableView reloadData]funcionaba bien. El error estaba realmente en la línea

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Cuando intenté verificar los valores de indexPath, no eran correctos como se requería.

Lo arreglé cambiando los valores en indexPathsArray.

Espero que esto ayude .

usuario5553647
fuente
1

Podría ser uno de los UITableViewDataSourcemétodos de protocolo

por

- tableView:numberOfRowsInSection:

debe devolver un número entero igual a la suma o resultado de

-insertRowsAtIndexPaths:withRowAnimation:y / o -deleteRowsAtIndexPaths:withRowAnimation:

por

- numberOfSectionsInTableView:

debe devolver un número entero igual a la suma o resultado de

-insertRowsAtIndexPaths:withRowAnimation: y / o -deleteSections:withRowAnimation:

Ted
fuente
0

Tuve el mismo problema con una base de datos principal. Si usa muchos FRC, solo necesita volver a cargar la vista de tabla dentro de cada condición en numberOfSectionsInTableView.

Privatus Privatus
fuente
2
También tengo este problema con Core Data. ¿Podría dar más detalles sobre su receta?
Drux
0

Me acaba de pasar esto mientras usaba Swift y un almacén de datos respaldado por FRC para administrar la información. Agregar una simple verificación a la operación de eliminación para evaluar la indexPath.section actual me permitió evitar una llamada extraña. Creo que entiendo por qué ocurre este problema ... Básicamente, cargo un mensaje en la fila superior siempre que mi conjunto de datos está vacío. Esto crea un problema de apagado por un problema, ya que hay una fila falsa.

Mi solución

... 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.
fuente
0

Simplemente verifique que llame a [yourTableView reloadData]; después de modificar la matriz de valores.

Evgeniy Kleban
fuente