我有一个带有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渲染,这样过渡会很快吗?
答案 0 :(得分:3)
[self.mapVC view];
[self.poiVC view];
您可以简单地询问视图控制器的视图,而不是对它做任何事情。这将返回视图,因此在需要时为您加载。缺点当然是你会增加你的启动时间。另请注意,当内存不足时,您的视图可能会被卸载,这会在切换到这些选项卡时再次导致拖延,但(至少会尝试)保持您的应用程序正常运行(通常被认为是一件好事)。
答案 1 :(得分:1)
我一直在努力解决同样的问题。我见过的所有答案都谈到试图通过拨打viewController.view
来预加载视图,但这不是主要的瓶颈,它最多只能节省几百毫秒。大多数实际渲染工作都在viewWillAppear
和viewDidAppear
之间进行,因此如果您想在初始转换期间避免延迟,则需要触发渲染。
为此,您需要在主视图中添加视图控制器作为子视图控制器。我发现执行此操作的最佳位置是主视图控制器上的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()
}
}