预渲染UITabBarController视图?

时间:2010-01-13 23:42:24

标签: iphone objective-c cocoa-touch

我有一个带有UITabBarController的应用程序,它管理一些UINavigationControllers,后者又管理各种UIViewControllers。

在3G手机上,我第一次通过TabBar按钮查看任何特定视图时,它是滞后的,但此后,它很快。这在3GS手机中并不明显。我的问题是如何强制这些视图进行预渲染?我已经尝试通过在启动时在不同的线程中调用它们来触发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渲染,这样过渡会很快吗?

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分: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()
    }
}