2010-01-13 9 views
2

J'ai une application avec un UITabBarController qui gère certains UINavigationControllers, qui à leur tour gèrent divers UIViewControllers.Visualisations de rendu UITabBarController avant le rendu?

Sur les téléphones 3G, la première fois que je vois une vue particulière via un bouton TabBar, c'est laggy, mais par la suite, c'est accrocheur. Ceci n'est pas perceptible avec les téléphones 3GS. Ma question est comment puis-je forcer ces vues à pré-rendre? J'ai essayé de déclencher les fonctions loadView en les appelant dans un thread différent au démarrage, mais cela ne fait rien que je ne pense pas. Par souci de clarté, voici un extrait abrégé de mon code pour montrer ce que je suis en train de faire. J'ai cinq contrôleurs de vue, mais je montre juste le code pour deux. Le poiVC est juste une sous-classe UITableViewController standard - je n'ai même pas de fonction personnalisée init ou loadView pour cela.

- (void)applicationDidFinishLaunching:(UIApplication *)application { 

    self.mapVC = [[MapViewController alloc] init]; 
    NavControlBar * mapNavBar = [[[NavControlBar alloc] initWithViewController:mapVC 
          withControlBar:[mapVC initBar]]autorelease]; 
    self.poiVC = [[POIViewController alloc] init]; 
    NavControlBar * poiNavBar = [[[NavControlBar alloc] initWithViewController:poiVC 
          withControlBar:[poiVC initBar]]autorelease]; 

    NSArray *tabViewControllerArray = [NSArray arrayWithObjects:mapNavBar, poiNavBar, nil]; 
    self.tbc.viewControllers = tabViewControllerArray; 
    self.tbc.delegate = self; 

    [mapVC release]; 
    [poiVC release]; 
    [window addSubview:tbc.view]; 

}

Puis-je obtenir le poiVC de rendre pendant que l'utilisateur regarde le premier écran, de sorte que la transition sera rapide?

+0

Pourquoi vous créez explicitement les barres de navigation ? Pourquoi ne pas simplement utiliser l'élément navigationItem dans vos contrôleurs de vue pour gérer la barre de navigation? Cela pourrait faire partie du problème. (Et qu'est-ce que NavControlBar?) – Nimrod

+0

Ces NavControlBars sont une classe stupide que j'ai créée pour ajouter des éléments arbitraires à un UINavigationBar, avant de comprendre comment UIBarButtonItems fonctionnait avec des vues personnalisées. Voici le référentiel github de la classe: http://github.com/andrewljohnson/NavControlBar. Je ne pense pas que ce soit le problème ... même si j'ai utilisé des navigateurs normaux, les vues ne sont pas restituées jusqu'à la première fois qu'elles s'affichent à l'écran, et je vais quand même voir le léger décalage du premier chargement. –

Répondre

2
[self.mapVC view]; 
[self.poiVC view]; 

Vous pouvez simplement demander la vue du contrôleur de vue et ne rien faire avec. Cela retournera la vue, et donc la chargera pour vous si nécessaire. L'inconvénient est bien sûr que vous allez augmenter votre temps de démarrage. Notez également que votre vue peut être déchargée lorsque la mémoire est faible, ce qui entraîne de nouveau des ralentissements lors du passage à ces onglets, mais (au moins essaie de) que votre application fonctionne (généralement considérée comme une bonne chose).

+0

J'ai déjà essayé ce qui suit: self.mapVC.view; - n'est-ce pas la même chose? Cela ne fait rien. –

+0

Ah ... c'est probablement parce que vous utilisez '-init', alors que vous devriez utiliser l'initialiseur désigné pour' UIViewController' (ou 'MapViewController' si vous en avez ajouté un). Pour 'UIViewController' ceci est '- (id) initNithNibName: (NSString *) bundle nibName: (NSBundle *) nibBundle'. –

+1

Je n'utilise pas Interface Builder ... et mes appels de fonction init [super init]. N'est-ce pas correct? –

1

J'ai eu du mal avec le même problème. Toutes les réponses que j'ai vues parlent d'essayer de précharger la vue en appelant viewController.view, mais ce n'est pas le goulot d'étranglement principal, et cela ne fait que sauver quelques centaines de millisecondes au mieux. La majorité du travail de rendu se produit entre viewWillAppear et viewDidAppear, vous devez donc déclencher un rendu si vous voulez éviter le décalage pendant votre transition initiale. Pour ce faire, vous devez ajouter vos contrôleurs de vue en tant que contrôleurs de vue enfant dans votre vue principale. J'ai trouvé que le meilleur endroit pour faire cela était dans le rappel viewDidAppear sur votre contrôleur de vue principale, car cela ne ralentira pas le chargement de votre vue principale. Et même si vous chargez et ajoutez les vues enfants sur le thread principal, cela ne semble pas bloquer l'interface utilisateur. (J'ai testé sur une vue qui a un jeu vidéo en arrière-plan.)

Voici le code Swift j'ai écrit une pré-rendu des contrôleurs de vue:

enum ViewPreloadingState { 
    case Pending, Preloading, Loaded 
} 
var viewPreloadingState = ViewPreloadingState.Pending 

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 

    if viewPreloadingState == .Pending { 
     viewPreloadingState = .Preloading 

     addChildViewController(loginViewController) 
     view.addSubview(loginViewController.view) 
     loginViewController.didMoveToParentViewController(self) 

     addChildViewController(signupViewController) 
     view.addSubview(signupViewController.view) 
     signupViewController.didMoveToParentViewController(self) 

     // Place view controllers off screen 
     let f = view.frame, 
      offScreenFrame = CGRect(x: f.width, y: 0, width: f.width, height: f.height) 
     loginViewController.view.frame = offScreenFrame 
     signupViewController.view.frame = offScreenFrame 
    } 
} 

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    if viewPreloadingState == .Preloading { 
     viewPreloadingState = .Loaded 

     loginViewController.willMoveToParentViewController(nil) 
     loginViewController.view.removeFromSuperview() 
     loginViewController.removeFromParentViewController() 

     signupViewController.willMoveToParentViewController(nil) 
     signupViewController.view.removeFromSuperview() 
     signupViewController.removeFromParentViewController() 
    } 
}