2010-01-13 122 views
2

我有一个UITabBarController管理一些UINavigationControllers,它反过来管理各种UIViewControllers的应用程序。预渲染UITabBarController视图?

在3G手机上,我第一次通过TabBar按钮查看任何特定的视图时,它是滞后的,但此后,它很活泼。这在3GS手机中并不明显。我的问题是如何强制这些视图进行预渲染?我尝试在启动时通过在不同的线程中调用loadView函数来触发loadView函数,但是这不会做任何我不认为的事情。

为了清楚起见,下面是我的代码中的一个缩写片段,用于显示我在做什么。我有五个视图控制器,但我只展示了两个代码。 poiVC只是一个标准的UITableViewController子类 - 我甚至没有自定义的init或loadView函数。

- (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]; 

}

我可以得到poiVC呈现在用户看第一屏,所以过渡将是快?

+0

你为什么要明确创建导航栏?为什么不在视图控制器中使用navigationItem来管理导航栏?这可能是问题的一部分。 (什么是NavControlBar?) – Nimrod 2010-01-14 00:07:44

+0

这些NavControlBars是我创建的一个哑类,用于在UINavigationBar中添加任意元素,然后才能理解UIBarButtonItems如何与自定义视图一起工作。以下是该类的github存储库:http://github.com/andrewljohnson/NavControlBar。我不认为这是问题...即使我使用正常的navigationControllers,视图也不会在第一次显示在屏幕上时呈现,并且在第一次加载时我仍会看到轻微的滞后。 – 2010-01-14 00:10:57

回答

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

你可以简单地询问视图控制器的视图,而不用做任何事情。这将返回视图,并因此在需要时加载它。当然,缺点是你会增加你的启动时间。另外请注意,当内存不足时,您的视图可能会被卸载,这会在切换到这些选项卡时再次导致延迟,但(至少会尝试)让您的应用程序保持运行(通常被认为是一件好事)。

+0

我以前试过以下这些:self.mapVC.view; - 这不是一回事吗?这没有做任何事情。 – 2010-01-14 00:34:33

+0

啊......这可能是因为你使用了'-init',而你应该为'UIViewController'(或者'MapViewController',如果你添加了一个)使用指定的初始化程序。对于'UIViewController',这是' - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle'。 – 2010-01-14 01:03:08

+1

我不使用Interface Builder ...,而我的init函数调用[super init]。这不正确吗? – 2010-01-14 01:10:32

1

我一直在努力解决同样的问题。我所见过的所有答案都是通过拨打电话viewController.view来预先加载视图,但这不是主要瓶颈,它最多只能节省几百毫秒。大部分实际渲染工作发生在viewWillAppearviewDidAppear之间,所以如果您想避免初始转换期间的延迟,您需要触发渲染。

为此,您需要将视图控制器添加为主视图中的子视图控制器。我发现最好的地方是在主视图控制器的viewDidAppear回调中,因为这不会减慢主视图的加载速度。即使您正在主线程上加载和添加子视图,它似乎也不会阻止UI。 (我一直在测试上,有一个背景视频播放一次观看)。

这里是SWIFT代码我已经写了预渲染一些视图控制器:

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() 
    } 
}