UIPageViewController se bloque lorsqu'il est returnné trop rapidement en cas de memory insuffisante

J'ai eu quelques problèmes de memory en raison du model de Xcode pour UIPageViewController en cache toutes datatables de la page, donc je l'ai changé pour charger les pages dynamicment, maintenant quand mon application reçoit un avertissement de memory faible, elle libère la memory pour la page non affichée l'user feuillette les pages très rapidement en appuyant sur le bord de l'écran, il se bloque toujours. Je devine que c'est parce qu'il ne peut pas libérer la memory assez rapidement quand didReceiveMemoryWarning est appelé. Si l'user bascule lentement, cela fonctionne correctement. J'ai limité la vitesse à laquelle l'user peut returnner les pages, mais cela arrive toujours. Je veux être en mesure de libérer de la memory chaque fois que la page est tournée, et ne pas avoir à attendre un avertissement de memory faible. J'utilise ARC. Y a-t-il un moyen de faire cela? Ou que puis-je faire d'autre pour éviter cela? Merci.

MODIFIER:

(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { NSUInteger index = [self indexOfViewController:(SinglePageViewControllerSuperclass *)viewController]; if ((index == 0) || (index == NSNotFound)) { return nil; } index--; return [self viewControllerAtIndex:index]; } (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { NSUInteger index = [self indexOfViewController:(SinglePageViewControllerSuperclass *)viewController]; if (index == NSNotFound || index == MAX_PAGE_INDEX) { return nil; } return [self viewControllerAtIndex:++index]; } 

Je pense que votre hypothèse est correcte, puisque j'ai aussi connu un comportement similaire: lorsque vous returnnez à la page suivante, aussi pour bien animer les choses, la nouvelle page est allouée avant que l'ancienne soit désallouée et il faut quelques fois pour la ancien à être désaffecté. Ainsi, lorsque vous returnnez assez vite, les objects sont alloués plus rapidement qu'ils ne sont désalloués et finalement (en fait, très bientôt), votre application est tuée en raison de l'utilisation de la memory. Le timeout de désallocation lors du basculement des pages devient assez évident si vous suivez l'allocation / désallocation de la memory dans Instruments .

Vous avez trois approches à cela, IMO:

  1. implémenter une méthode «light» viewDidLoad (en fait, toute l'initialisation / séquence d'affichage initiale): dans certaines applications, il est logique, par exemple, de charger une image basse résolution au lieu de l'image haute résolution qui sera affichée; ou, en retardant légèrement l'allocation de ressources supplémentaires dont votre page a besoin (access db, son, etc.);

  2. utiliser un pool de pages, disons un tableau de trois pages (ou 5, cela dépend de votre application), que vous continuez à "réutiliser" afin que le profil de la memory de votre application rest stable et évite les pics;

  3. examiner attentivement la façon dont vous allouez et libérez de la memory; dans ce sens, vous lisez souvent que autorelease ajoute une certaine "inertie" au mécanisme release / deallocation, et c'est assez facile à comprendre: si vous avez un object autoreleased, il sera libéré par son pool de publication uniquement lorsque vous parcourez le boucle principale (ceci est vrai pour le pool de versions principal); Par conséquent, si vous avez une longue séquence de methods qui sont appelées lors du returnnement de la page, la release / dealloc se produira plus tard.

Il n'y a pas de solution magique pour l'optimization de l'utilisation de la memory, c'est un travail assez détaillé et difficile, mais IME vous permettra de réduire le profil de memory de votre application si vous examinez votre code et appliquez ces 3 directives. En particulier, inspecter les pics d'allocation de memory dans les instruments et essayer de comprendre à quoi ils se rapportent est extrêmement puissant.

Voici un changement supplémentaire que j'ai fait, que quelqu'un pourrait find utile:

Fondamentalement, je permets seulement un nouveau tour de page pour commencer si le précédent a fini.

J'utilise le projet PageViewController par défaut de Apple comme model. J'utiliserai donc les termes définis dans ce projet.

Chaque fois qu'un VC de page est demandé via viewControllerAtIndex:, je définis une valeur booleanne sur ModelController appelée ' shouldDenyVC ' sur YES .

Dans mon EbookViewController qui est le délégué de UIPageViewController, je capture les reconnaisseurs de gestes et j'atsortingbue EbookViewController en tant que délégué:

 self.view.gestureRecognizers = self.pageViewController.gestureRecognizers; for (UIGestureRecognizer *gr in self.view.gestureRecognizers) { gr.delegate = self; } 

Ensuite, je suis capable de refuser une page en refusant les reconnaisseurs de gestes:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch { if (_modelController.shouldDenyPageTurn == YES) { return FALSE; } return TRUE; } 

Et enfin, je _modelController.shouldDenyPageTurn = NO à la fin de la méthode déléguée UIPageViewController pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

J'ai également dû définir _modelController.shouldDenyPageTurn = NO à la fin de tout préchargement afin que les virages de la page soient autorisés à partir de la chauve-souris.

À l'heure actuelle, il existe un bogue dans iOS5 qui provoque une perte de memory dans une vue de défilement.

Avez-vous essayé de profiler votre application dans des instruments vérifiant les allocations et les memory leaks?

Vous pouvez simuler un avertissement de memory faible soit dans le simulateur (matériel -> simuler un avertissement de faible memory). Ou vous pouvez le faire via le code, (callbackez-vous juste de supprimer après le debugging, car votre application sera rejetée!)

 [[UIApplication sharedApplication] performSelector:@selector(_performMemoryWarning)]; 

Si vous utilisez strong propriétés strong ou de retain , réglez-les sur nil après que vous en ayez fini avec elles et ARC libèrera la memory vers laquelle elles pointent en arrière-plan.

Si vous créez beaucoup d'objects temporaires (objects qui ne sont pas des propriétés ou non alloués), insérez un pool autorelease:

 @autoreleasepool { } 

Et enfin, montrez du code et nous pouvons mieux vous aider.

Cela peut être dû au rendu. Quand le flipper est trop rapide, la memory et la CPU utilisées en redessinant la "Page" augmentent rapidement. Si les vues que vous avez utilisées dans UIPageViewController sont basées sur CALayer et contiennent trop de pages, le fait de returnner trop vite va certainement provoquer le crash de l'application.

Une solution consiste à personnaliser la couche et à mettre en cache le résultat du rendu. Re-rendre le contenu seulement quand doit. Mais le cache peut augmenter l'utilisation de la memory.

Puisque vous n'avez pas publié de code, il est difficile de deviner où se situe exactement votre problème.

  1. Pour forcer le déchargement d'une vue, vous pouvez replace viewDidDisappear: méthode des classs viewcontroller qui apparaissent dans UIPageViewController .

    Le code ressemblerait à:

     - (void)viewDidDisappear:(BOOL)animated { [self didReceiveMemoryWarning]; } 

    Si vous avez également didReceiveMemoryWarning surchargé, n'oubliez pas d'appeler [super didReceiveMemoryWarning]; à partir de cela.

  2. Il peut aussi y avoir une certaine confusion sur le UIPageViewControllerDataSource methods UIPageViewControllerDataSource – vous pourriez avoir des «fils mixtes». Vérifiez la réponse acceptée ici .