J'ai un comportement étrange avec presentViewController:animated:completion
. Ce que je fais est essentiellement un jeu de devinettes.
J'ai un UIViewController
(frequencyViewController) contenant un UITableView
(frequencyTableView). Lorsque l'utilisateur appuie sur la ligne en questionTableView contenant la bonne réponse, une vue (correctViewController) doit être instanciée et sa vue doit glisser vers le haut à partir du bas de l'écran, sous la forme d'une vue modale. Cela indique à l'utilisateur qu'il a une réponse correcte et réinitialise le FrequencyViewController derrière lui, prêt pour la question suivante. correctViewController est rejeté en appuyant sur un bouton pour révéler la question suivante.
Tout cela fonctionne correctement à chaque fois, et la vue correcteViewController apparaît instantanément aussi longtemps que l' presentViewController:animated:completion
a animated:NO
.
Si je définis animated:YES
, correctViewController est initialisé et fait des appels à viewDidLoad
. Cependant viewWillAppear
, viewDidAppear
et le bloc d'achèvement de presentViewController:animated:completion
ne sont pas appelés. L'application reste juste là et affiche encore frequencyViewController jusqu'à ce que je fasse un deuxième tap. Maintenant, viewWillAppear, viewDidAppear et le bloc de complétion sont appelés.
J'ai enquêté un peu plus, et ce n'est pas simplement un autre robinet qui le fera continuer. Il semble que si j'incline ou secoue mon iPhone, cela peut également provoquer le déclenchement de viewWillLoad, etc. Cela se produit sur un vrai iPhone et dans le simulateur, ce que j'ai prouvé en envoyant la commande shake au simulateur.
Je ne sais vraiment pas quoi faire à ce sujet ... J'apprécierais vraiment toute aide que n'importe qui peut me fournir.
Merci
Voici mon code. C'est assez simple ...
Il s'agit du code en questionViewController qui agit en tant que délégué de la 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];
}];
}
}
C'est l'ensemble du 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
Éditer:
J'ai trouvé cette question plus tôt: UITableView et presentViewController prennent 2 clics pour s'afficher
Et si je change mon didSelectRow
code pour cela, cela fonctionne très souvent avec l'animation ... Mais c'est compliqué et ne comprend pas pourquoi cela ne fonctionne pas en premier lieu. Donc je ne compte pas ça comme une réponse ...
- (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];
}];
}
la source
presentViewController:
est censée déclencher commence avec un gros retard. Cela semble être un bogue dans iOS 7 et est également discuté dans les forums Apple Dev.Réponses:
J'ai rencontré le même problème aujourd'hui. J'ai creusé dans le sujet et il semble que cela soit lié au sommeil de la boucle principale.
En fait, c'est un bogue très subtil, car si vous avez la moindre animation de rétroaction, les minuteries, etc. dans votre code, ce problème ne se posera pas car la boucle d'exécution sera maintenue en vie par ces sources. J'ai trouvé le problème en utilisant un
UITableViewCell
qui avait sonselectionStyle
ensemble àUITableViewCellSelectionStyleNone
, de sorte qu'aucune animation de sélection a déclenché le runloop après le gestionnaire de sélection de ligne RAN.Pour résoudre ce problème (jusqu'à ce qu'Apple fasse quelque chose), vous pouvez déclencher la boucle d'exécution principale de plusieurs manières:
La solution la moins intrusive est d'appeler
CFRunLoopWakeUp
:Ou vous pouvez mettre en file d'attente un bloc vide dans la file d'attente principale:
C'est drôle, mais si vous secouez l'appareil, cela déclenchera également la boucle principale (il doit traiter les événements de mouvement). Même chose avec les robinets, mais c'est inclus dans la question d'origine :) De plus, si le système met à jour la barre d'état (par exemple, l'horloge se met à jour, la force du signal WiFi change, etc.), cela réveillera également la boucle principale et présentera la vue manette.
Pour toute personne intéressée, j'ai écrit un projet de démonstration minimal du problème pour vérifier l'hypothèse de la boucle d'exécution: https://github.com/tzahola/present-bug
J'ai également signalé le bogue à Apple.
la source
Vérifiez ceci: https://devforums.apple.com/thread/201431 Si vous ne voulez pas tout lire - la solution pour certaines personnes (y compris moi) était de faire l'
presentViewController
appel explicitement sur le fil principal:Swift 4.2:
Objectif c:
Probablement iOS7 gâche les fils
didSelectRowAtIndexPath
.la source
Je l'ai contourné dans Swift 3.0 en utilisant le code suivant:
la source
present
un rappel de fermeture.L'appel
[viewController view]
sur le contrôleur de vue présenté a fait l'affaire pour moi.la source
Je serais curieux de voir ce que
[self setUpViewForNextQuestion];
fait.Vous pouvez essayer d'appeler
[self.correctViewController.view setNeedsDisplay];
à la fin de votre bloc d'achèvementpresentViewController
.la source
Correct Guess: 1 kHz 18:04:57.173 Frequency[641:60b] [HFBCorrectViewController initWithNibName:bundle:] 18:04:57.177 Frequency[641:60b] [HFBCorrectViewController viewDidLoad]
Maintenant, rien ne se passe avant: Appuyez sur 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]
J'ai écrit une extension (catégorie) avec une méthode swizzling pour UIViewController qui résout le problème. Merci à AX et NSHipster pour les conseils d'implémentation ( swift / objective-c ).
Rapide
Objectif c
la source
Vérifiez si votre cellule dans le storyboard a Selection = none
Si c'est le cas, changez-le en bleu ou en gris et cela devrait fonctionner
la source
Version XCode: 9.4.1, Swift 4.1
Dans mon cas, cela se produit lorsque je tape sur la cellule et que je passe à une autre vue. Je débogue dans le plus profond et il semble que cela se produise à l'intérieur à
viewDidAppear
cause de contient le code suivantpuis j'ai ajouté le segment de code ci-dessus à l'intérieur
prepare(for segue: UIStoryboardSegue, sender: Any?)
et fonctionne parfaitement.D'après mon expérience, ma solution est la suivante: si nous espérons faire de nouvelles modifications (par exemple, recharger la table, désélectionner la cellule sélectionnée, etc.) pour la vue de la table lorsque vous revenez de la deuxième vue, utilisez alors déléguer au lieu
viewDidAppear
et en utilisant letableView.deselectRow
code ci-dessus segment avant de déplacer le deuxième contrôleur de vuela source