/ / EXC_BAD_ACCESS en [self.tableView reloadData] - iphone, objectivo-c, ios, uitableview, exc-bad-access

EXC_BAD_ACCESS en [self.tableView reloadData] - iphone, objectivo-c, ios, uitableview, exc-bad-access

Estoy haciendo una aplicación simple que hace algunos cálculos. Algunos de estos cálculos son bastante complejos, por lo que puede tomar un tiempo obtener el resultado. Estoy usando UITableView para permitir que el usuario ingrese los valores. Luego, después de hacer clic en el botón "Calcular", hago un simple UIView con un UIActivityIndicatorView en él y lo puse en el medio de la pantalla. Y luego llamo al método de cálculo en segundo plano. Algún código:

    self.activityIndicatorView = [[UIView alloc]initWithFrame:CGRectMake(320/2 - 50, (480 - 64)/2 - 50, 100, 100)];
self.activityIndicatorView.layer.cornerRadius = 10.0f;
self.activityIndicatorView.backgroundColor = [UIColor colorWithRed:0. green:0. blue:0. alpha:0.7];
UIActivityIndicatorView *actInd = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
actInd.frame = CGRectMake((100 - actInd.frame.size.width) / 2, (100 - actInd.frame.size.height) / 2, actInd.frame.size.width, actInd.frame.size.height);
[actInd startAnimating];
[self.activityIndicatorView addSubview:actInd];
[self.activityIndicatorView bringSubviewToFront:actInd];
[self.view addSubview:self.activityIndicatorView];
[self.view bringSubviewToFront:self.activityIndicatorView];
[self performSelectorInBackground:@selector(calculateAllThatShizzle) withObject:nil];

Como ves, es bastante simple. Pero si el teclado aún está visible, se bloquea (EXC_BAD_ACCESS) cuando llegue [self.tableView reloadData] en el -(void)calculateAllThatShizzle método con eso en el registro:

2012-03-23 11:06:32.418 MyApp[869:5c07] bool _WebTryThreadLock(bool), 0x6adb270: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
1   WebThreadLock
2   -[UITextRangeImpl isEmpty]
3   -[UITextRange(UITextSelectionAdditions) _isCaret]
4   -[UITextSelectionView setCaretBlinks:]
5   -[UIKeyboardImpl setCaretBlinks:]
6   -[UIKeyboardImpl setDelegate:force:]
7   -[UIKeyboardImpl setDelegate:]
8   -[UIPeripheralHost(UIKitInternal) _reloadInputViewsForResponder:]
9   -[UIResponder _finishResignFirstResponder]
10  -[UIResponder resignFirstResponder]
11  -[UITextField resignFirstResponder]
12  -[UITableView reloadData]
13  -[ChildViewController calculateAllThatShizzle]
14  -[NSThread main]
15  __NSThread__main__
16  _pthread_start
17  thread_start

Entonces, el problema es que está tratando de hacer algo con el teclado desde un hilo de fondo. He intentado recorrer las celdas y llamar [cell.rightTextField resignFirstResponder], pero no ayuda. También intenté usar eso

-(void)reloadTableViewData {
[self.tableView reloadData];
}
-(void)calculateAllThatShizzle {
//some code omitted - code that uses UIKit
if ([dob timeIntervalSinceDate:calcDate]>0) {
[errorButton setTitle:@"Calculation Date must be more than Date of Birth" forState:UIControlStateNormal];
errorButton.hidden = NO;
[self.activityIndicatorView removeFromSuperview];
self.activityIndicatorView = nil;
return;
}
[self performSelectorOnMainThread:@selector(reloadTableViewData) withObject:nil waitUntilDone:NO];
}

pero tampoco ayuda. Estoy usando ELCTextfieldCell

Cualquier ayuda será apreciada.

Gracias

PD Revisé algunas otras preguntas sobre EXC_BAD_ACCESS en reloadData, pero no cubre el problema que tengo

P.P.S. También puedo ejecutar los cálculos en el hilo principal, pero luego la GUI deja de responder y el indicador de actividad no aparece

Respuestas

1 para la respuesta № 1

prueba este código

for(int i=0;i<[tblViewData count];i++)
{
if([[(ELCTextfieldCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]] rightTextField] isFirstResponder])
{
[[(ELCTextfieldCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]] rightTextField] resignFirstResponder];
}
}

cambia de acuerdo a ti.


2 para la respuesta № 2

Sugerencia:

  • hacer la tablaVer el primer respondedor antes de llama a CalculateAllThatShizzle, es decir, obliga al primer respondedor actual a renunciar y así descarta su teclado
  • y luego DEFERIR la llamada al CalculateAllThatShizzle después de que se haya completado el ciclo de ejecución actual, es decir, asegurarse de que el código para descartar el teclado se ejecute en un momento adecuado

Entonces, algo como esto:

[[self tableView] becomeFirstReponder]; // will dismiss keyboard
[[self performSelector: @selector(startBackgroundStuff) withObject: nil afterDelay: 0.0];

Luego, en su startBackgroundStuff puede poner su:

[self performSelectorInBackground:@selector(calculateAllThatShizzle) withObject:nil];

En el método definitivamente desea asegurarse de que se llame al método reloadData en el hilo principal. La forma en que lo ha hecho se ve bien. También puede hacer lo siguiente:

dispatch_async(dispatch_get_main_queue(), ^{
[self reloadTableViewData];
});

(No sé si uno es mejor que el otro, solo que lo que sigue definitivamente funciona de manera confiable).

Comentario complementario

En CalculateAllThatShizzle está realizando una llamada UIKit desde el fondo en algunas condiciones, es decir. [self.activityIndicatorView removeFromSuperview]; Es probable que cause un choque. Las llamadas UIKit deben estar en el hilo principal.

En