我有一个从选项卡式应用程序模板创建的应用程序。 (ARC,iOS 4)
问题
现在,当ModalViewCont在屏幕上,按Home键将应用程序置于后台并在获得应用程序后,关闭ModalViewCont不会带回ViewCont2的视图,而是带有底部标签栏的黑屏。没有放置应用程序背景/前景就会发生同样的事情;如果在点击2.标签之前点击了其他标签。(编辑:只有在viewWillDisappear中将self.view设置为nil而不是viewDidDisappear时才会发生这种情况。)
我确定ViewCont2加载了一个新视图(检查了它的引用)但是视图的superview是nil所以新视图不会显示而是显示黑屏。
无效的事情
我考虑过的解决方案;
_
if (self.view.superview == nil)
{
self.tabBarController.selectedViewController = nil;
self.tabBarController.selectedViewController = self;
}
问题
编辑:似乎早于调用viewDidLoad时(即在viewWillDisappear而不是viewDidDisappear中调用视图时),不会设置superview。
答案 0 :(得分:6)
看起来很奇怪,但你的建议(1)确实是解决这个问题的正确方法:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.view.superview) { // check if view has been added to view hierarchy
self.tabBarController.selectedViewController = nil;
self.tabBarController.selectedViewController = self;
}
}
你的第二个建议对性能有好处(因为视图加载是一项昂贵的操作) - 但它无法解决问题。在以下情况下,您也可以使用黑屏而不将视图设置为nil(在iOS模拟器中测试):
通常,您可以假设在viewDidLoad中设置了view属性,并且在viewWillAppear + viewDidAppear中,视图已添加到视图层次结构中;所以superview应该在那时(这里superview是类UIViewControllerWrapperView的tabbarcontroller的私有视图)。但是在我们的情况下,虽然重新加载视图(在应用程序恢复时),但它不会添加到视图层次结构中,从而导致黑屏。这似乎是UITabBarController中的一个错误。
该解决方法强制再次执行外观选择器。因此,将再次调用viewWillAppear,这次使用superview。 viewDidAppear也会被调用两次!
将self.view设置为nil是可以的,但在大多数情况下不应该是必需的。让系统决定何时卸载视图(iOS可以在内存变低时卸载视图)。视图控制器代码的设计应该能够在不重新加载视图的情况下随时重新配置UI。
答案 1 :(得分:1)
您无法完全控制何时加载和卸载视图,并且您不应自己手动加载/卸载视图。
相反,您应该将视图加载/卸载视为完全取决于UIViewController
的内容,而您只负责:
loadView
来实现实际加载。viewDidLoad
,viewWillUnload
和viewDidUnload
回调,当 决定加载/卸载其视图时,视图控制器会调用这些回调。< / LI>
当上述回调将被调用时,你无法完全控制这一事实会对应该进入的内容产生影响。
在您的情况下,如果我理解正确,每当ViewCont2的视图消失时,您想要重置它,以便当它再次出现时它将处于某种“干净”状态。我会在某种方法中实现此状态重置,并从viewDidLoad
和viewDidDisappear
调用它。或者,您可以在viewWillAppear
中使用“干净”逻辑。
或者您可能只想在点击当前按钮时清理ViewCont2的视图?在这种情况下,请在viewDidLoad
中以及点击按钮时清除视图。
答案 2 :(得分:1)
我提供的是当模态视图控制器处于活动状态并且您关闭视图时,您将新视图添加到导航视图控制器viewControllers,然后告知该视图删除其前一个。
您可以使用my project来查看您认为它是否适合您。
编辑:我对所选答案的评论是,这项技术现在显然有效,但我自己很难跟进它。我的项目中的代码以简单直接的方式使用系统 - 当模态视图被告知自己解散时,它调用一个方法(可以在任何类中),为导航控制器的数组添加一个新视图,然后解散自己。有一段时间,同时有两个视图控制器,新的视图控制器堆叠在旧视图控制器上。当新的视图控制器出现时,基于它静默地看到一个标志,并在幕后从nab条的堆栈中删除不需要的viewController,而poof,它就会消失。答案 3 :(得分:1)
我找到了UITabBarController错误的实际解决方案(内存警告,应用程序返回/前台,关闭模式)。使用UITabBarController作为根视图控制器是bug的原因。因此,我们可以使用另一个视图控制器作为根视图控制器并从中显示标签栏。我在iOS 5.1模拟器上测试了它。
当然,额外的UIViewController的开销受到争议。此外,它反对Apple文档;
与其他视图控制器不同,标签栏界面不应该作为另一个视图控制器的子项安装。UITabBarController Class Reference
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// A root view controller other than the actual UITabBarController is required.
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, ..., nil];
[self.window.rootViewController
presentModalViewController:self.tabBarController animated:NO];
}
答案 4 :(得分:0)
我找到了其他解决方案;
第一个引发警告:“虽然有根视图控制器,但应用程序窗口应该在应用程序启动结束时具有根视图控制器”。
虽然看起来像kludgy,但临时视图控制器将与第一个一起发布。
- (void) tabBarBlankScreenFix1
{
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
[self.window addSubview:self.tabBarController.view];
self.window.rootViewController = self.tabBarController;
}
- (void) tabBarBlankScreenFix2
{
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
[self.window addSubview:self.tabBarController.view];
}
答案 5 :(得分:-1)
我认为你不应该将视图分配给nil。 如果我理解正确,您希望每次出现视图时刷新/重新加载内容。 因此,不应将视图设置为nil,而应尝试刷新它。您可以通过添加:
来实现 - (void)viewWillAppear{
[self.view setNeedsDisplay];}
如果我理解你的问题,请告诉我