Estoy teniendo un comportamiento extraño con presentViewController:animated:completion
. Lo que estoy haciendo es esencialmente un juego de adivinanzas.
Tengo un UIViewController
(FrequencyViewController) que contiene un UITableView
(FrequencyTableView). Cuando el usuario toca la fila en questionTableView que contiene la respuesta correcta, se debe crear una instancia de una vista (correctViewController) y su vista debe deslizarse hacia arriba desde la parte inferior de la pantalla, como una vista modal. Esto le dice al usuario que tiene una respuesta correcta y restablece el FrequencyViewController detrás de él listo para la siguiente pregunta. correctViewController se descarta al presionar un botón para revelar la siguiente pregunta.
Todo esto funciona correctamente cada vez, y la vista de la vista correcta de ViewController aparece instantáneamente siempre que lo presentViewController:animated:completion
haya hecho animated:NO
.
Si lo configuro animated:YES
, correctViewController se inicializa y realiza llamadas a viewDidLoad
. Sin embargo viewWillAppear
, viewDidAppear
y el bloque de finalización de presentViewController:animated:completion
no se llaman. La aplicación se queda ahí y sigue mostrando FrequencyViewController hasta que hago un segundo toque. Ahora, se llaman viewWillAppear, viewDidAppear y el bloque de finalización.
Investigué un poco más, y no es solo otro toque lo que hará que continúe. Parece que si inclino o sacudo mi iPhone, esto también puede hacer que active viewWillLoad, etc. Es como si estuviera esperando cualquier otra entrada del usuario antes de que progrese. Esto sucede en un iPhone real y en el simulador, lo cual probé enviando el comando de agitar al simulador.
Realmente no sé qué hacer al respecto ... Realmente agradecería cualquier ayuda que alguien pueda brindar.
Gracias
Aquí está mi código. Es bastante simple ...
Este es el código en questionViewController que actúa como delegado de questionTableView
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
{
// If guess was wrong, then mark the selection as incorrect
NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
}
else
{
// If guess was correct, show correct view
NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
self.correctViewController = [[HFBCorrectViewController alloc] init];
self.correctViewController.delegate = self;
[self presentViewController:self.correctViewController animated:YES completion:^(void){
NSLog(@"Completed Presenting correctViewController");
[self setUpViewForNextQuestion];
}];
}
}
Este es el conjunto de correctViewController
@implementation HFBCorrectViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
NSLog(@"[HFBCorrectViewController initWithNibName:bundle:]");
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"[HFBCorrectViewController viewDidLoad]");
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"[HFBCorrectViewController viewDidAppear]");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)close:(id)sender
{
NSLog(@"[HFBCorrectViewController close:sender:]");
[self.delegate didDismissCorrectViewController];
}
@end
Editar:
Encontré esta pregunta antes: UITableView y presentViewController necesitan 2 clics para mostrarse
Y si cambio mi didSelectRow
código a este, funciona muy a tiempo con la animación ... Pero es complicado y no tiene sentido por qué no funciona en primer lugar. Entonces no cuento eso como una respuesta ...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
{
// If guess was wrong, then mark the selection as incorrect
NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
// [cell setAccessoryType:(UITableViewCellAccessoryType)]
}
else
{
// If guess was correct, show correct view
NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
////////////////////////////
// BELOW HERE ARE THE CHANGES
[self performSelector:@selector(showCorrectViewController:) withObject:nil afterDelay:0];
}
}
-(void)showCorrectViewController:(id)sender
{
self.correctViewController = [[HFBCorrectViewController alloc] init];
self.correctViewController.delegate = self;
self.correctViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:self.correctViewController animated:YES completion:^(void){
NSLog(@"Completed Presenting correctViewController");
[self setUpViewForNextQuestion];
}];
}
fuente
presentViewController:
se supone que se dispara comienza con un gran retraso. Esto parece ser un error en iOS 7 y también se comenta en los foros de desarrollo de Apple.Respuestas:
Hoy me he encontrado con el mismo problema. Profundicé en el tema y parece que está relacionado con el runloop principal dormido.
En realidad, es un error muy sutil, porque si tiene la más mínima animación de retroalimentación, temporizadores, etc. en su código, este problema no saldrá a la luz porque estas fuentes mantendrán vivo el runloop. Encontré el problema al usar un
UITableViewCell
que estabaselectionStyle
configurado enUITableViewCellSelectionStyleNone
, de modo que ninguna animación de selección activó el runloop después de que se ejecutó el controlador de selección de filas.Para solucionarlo (hasta que Apple haga algo), puede activar el runloop principal por varios medios:
La solución menos intrusiva es llamar
CFRunLoopWakeUp
:O puede poner un bloque vacío en la cola principal:
Es gracioso, pero si agitas el dispositivo, también activará el bucle principal (tiene que procesar los eventos de movimiento). Lo mismo con los toques, pero eso está incluido en la pregunta original :) Además, si el sistema actualiza la barra de estado (por ejemplo, las actualizaciones del reloj, la intensidad de la señal WiFi cambia, etc.), eso también activará el bucle principal y presentará la vista. controlador.
Para cualquier persona interesada, escribí un proyecto de demostración mínimo del problema para verificar la hipótesis de runloop: https://github.com/tzahola/present-bug
También le informé del error a Apple.
fuente
Mira esto: https://devforums.apple.com/thread/201431 Si no quieres leerlo todo, la solución para algunas personas (incluido yo) fue hacer la
presentViewController
llamada explícitamente en el hilo principal:Rápido 4.2:
C objetivo:
Probablemente iOS7 esté arruinando los hilos
didSelectRowAtIndexPath
.fuente
Lo omití en Swift 3.0 usando el siguiente código:
fuente
present
para una devolución de llamada de cierre.Llamar
[viewController view]
al controlador de vista que se presenta fue el truco para mí.fuente
Tendría curiosidad por ver qué
[self setUpViewForNextQuestion];
hace.Puede intentar llamar
[self.correctViewController.view setNeedsDisplay];
al final de su bloque de finalización enpresentViewController
.fuente
Correct Guess: 1 kHz 18:04:57.173 Frequency[641:60b] [HFBCorrectViewController initWithNibName:bundle:] 18:04:57.177 Frequency[641:60b] [HFBCorrectViewController viewDidLoad]
Ahora no pasa nada hasta: Tap 218:05:00.515 Frequency[641:60b] [HFBCorrectViewController viewDidAppear] 18:05:00.516 Frequency[641:60b] Completed Presenting correctViewController 18:05:00.517 Frequency[641:60b] [HFBFrequencyViewController setUpViewForNextQuestion]
Escribí la extensión (categoría) con el método swizzling para UIViewController que resuelve el problema. Gracias a AX y NSHipster por las sugerencias de implementación ( swift / aim -c ).
Rápido
C objetivo
fuente
Compruebe si su celda en el guión gráfico tiene Selection = none
Si es así, cámbielo a azul o gris y debería funcionar
fuente
XCode Vesion: 9.4.1, Swift 4.1
En mi caso, esto sucede cuando toco celda y me muevo para la otra vista. Depuraré en lo más profundo y parece que sucede dentro
viewDidAppear
debido a que contiene el siguiente códigoluego agregué el segmento de código anterior dentro
prepare(for segue: UIStoryboardSegue, sender: Any?)
y funcionó perfecto.Según mi experiencia, mi solución es, si esperamos hacer algún cambio nuevo (por ejemplo, recargar la tabla, deseleccionar la celda seleccionada, etc.) para la vista de la tabla cuando regrese nuevamente desde la segunda vista, entonces use delegar en lugar de
viewDidAppear
usar eltableView.deselectRow
código anterior segmento antes de mover el segundo controlador de vistafuente