2010-11-29 31 views
2

J'ai un UINavigationController, et j'appuie sur le contrôleur de vue racine pour passer au contrôleur de vue suivant. Ce second contrôleur de vue est assez "lourd", en ce sens qu'il a beaucoup d'initialisation et de sous-vues.Faible fréquence d'images pendant la transition push UINavigationController

Mon problème est le suivant: l'animation de transition fonctionne terriblement. Fondamentalement, l'animation souffre d'un taux de trame très faible (j'obtiens peut-être 3-4 images au total de l'animation "push").

J'ai essayé une variété de techniques différentes, y compris deux méthodes différentes pour animer manuellement la transition. Dans tous les cas, les premières 0.4-0.7 secondes de l'animation souffrent de ce pauvre framerate. Si je mets la transition à prendre 5 secondes, par exemple, la première demi-seconde ou moins fonctionne mal, mais le reste de l'animation est agréable et lisse. Cela m'amène à croire que quelque chose se passe au début de la transition, ce qui fait que le périphérique s'anime à un très faible taux de framerate. Après avoir injecté beaucoup d'instructions NSLog dans mon code, j'ai vu deux choses se produire. Tout d'abord, évidemment, la deuxième vue est en train d'être paresseuse pendant la poussée. J'ai corrigé ceci en accédant au getter sur la propriété view avant d'exécuter le push. Je peux confirmer que cela se traduit par toute l'initialisation qui se produit avant le début de l'animation poussée. Deuxièmement, mon application reçoit la plupart du temps un avertissement de mémoire faible pendant la transition. Cependant, même dans les cas où je ne reçois pas l'avertissement de la mémoire, l'animation fonctionne tout aussi mal - ce qui me fait croire qu'aucune de ces choses n'est la cause.

Ma question: Quelqu'un at-il connu d'autre faible framerate sur une animation de transition push UINavigationController, mais seulement pour les premières 0,4-0,7 secondes de l'animation? Y a-t-il quelque chose d'autre qui se cache derrière les coulisses et peut-on faire quelque chose?

Pour référence, voici mon code actuel qui charge et pousse à la vue suivante. J'accède de manière ciblée au getter de vue afin de forcer la vue à se charger et à s'initialiser avant la transition (principalement pour exclure cela comme problème). Ce code est exécuté sur le thread principal en utilisant performSelectorOnMainThread::: en réponse à un rappel de service Web.

PlayingFieldViewController *v = [[PlayingFieldViewController alloc] initWithNibName:@"PlayingFieldView" bundle:[NSBundle mainBundle]]; 
UIView *lazy = v.view; 
[appDelegate.navigationController pushViewController:v animated:YES]; 
[v release]; 

J'ai aussi essayé quelques autres techniques d'animation, tous avec le même résultat:

CATransition *transition = [CATransition animation]; 
transition.duration = 1.0; 
transition.type = kCATransitionPush; 
transition.subtype = kCATransitionFromRight; 
[appDelegate.navigationController.view.layer addAnimation:transition forKey:kCATransition]; 
[appDelegate.navigationController pushViewController:v animated:NO]; 

et:

[UIView 
    transitionWithView:appDelegate.navigationController.view 
    duration:1.0 
    options:UIViewAnimationOptionTransitionCurlUp 
    animations:^{ 
    [appDelegate.navigationController pushViewController:v animated:NO]; 
    } 
    completion:NULL]; 
+0

Tout d'abord, les modifications de l'interface utilisateur doivent toujours se trouver sur le thread principal. Mais aussi, à quoi ressemble votre méthode 'viewWillAppear:'? –

+0

Le code est en cours d'exécution sur le thread principal, mais cela ne fait aucune différence. En fait, je n'avais pas de méthode viewWillAppear: bien que j'y aie ajouté une petite quantité de choses. Avec ou sans viewWillAppear :, le problème persiste. –

Répondre

3

Après d'autres essais, j'ai pu diagnostiquer le problème. La deuxième vue en cause comprend plusieurs UIImageViews.Supprimer ces vues ou les masquer résout le problème. Ce qui m'a découragé, c'est que seule la première partie de l'animation souffrait de problèmes de fréquence d'images, alors que le reste de l'animation était parfaitement fluide (dans le cas d'animations plus longues). Cela me montre que l'appareil est tout à fait capable d'animer la transition en douceur, même avec toutes les sous-vues présentes. Je ne suis toujours pas un expert en composition iOS, mais je suppose que les différentes couches sont disposées et mises en cache, menant au ralentissement. La solution consiste à pousser vers la vue avec la plupart des sous-vues cachées, puis à les montrer en utilisant une autre animation une fois que la vue est visible.

0

Je n'ai pas trébuché sur cela avec le contrôleur de navigation mais j'ai eu à peu près le même résultat lors de la mise à jour d'une vue de table à partir d'un autre thread, l'interface utilisateur était très lent à mettre à jour au début, mais après un court délai, tout se passait à nouveau. Comme Justin le souligne dans un commentaire, vous devriez faire un travail d'interface utilisateur sur le thread principal. Une façon simple d'y arriver est envelopper votre appel à l'interface utilisateur dans un bloc de GCD:

dispatch_sync(dispatch_get_main_queue(), ^{ 
// Do UI stuff here 
}); 

ou utilisez

performSelectorOnMainThread:withObject:waitUntilDone:

+0

J'ai déplacé le code dans un nouveau sélecteur et utilisé performSelectorOnMainThread: withObject: waitUntilDone :. Cela n'a malheureusement eu aucun effet - le problème persiste toujours. –