更新:请阅读底部的最终更新!下面的原始答案+更新可能没有用!
我们刚刚遇到了完全相同的问题。有时我想知道 Apple 是否真的用任何类似于现实用例的东西来测试他们编写的类,因为 UISplitViewController 并不是他们最好的时刻。
问题是,当您在拆分视图中替换主视图控制器时,UISplitViewController 内的代码不会更新其弹出框控制器的 contentViewController 属性。结果是popover控制器仍然有一个过期视图控制器的句柄,导致在纵向模式下出现旧的UI,甚至内存错误。
这是我们的解决方法。
我将假设您有一个符合 UISplitViewControllerDelegate 的类,它将 popoverController 存储为类属性(请参阅 UISplitViewController 的标准示例代码)。
在设置新的主视图控制器时,您还需要更新 contentViewController,如下所示:
mySplitViewController.viewControllers
= [NSArray arrayWithObjects:newMasterController, detailController, nil];
// in the cases where the uisplitview has already shown a popovercontroller,
// we force the popovercontroller to update its content view controller.
// This ensures any old content view in popover actually gets released by
// the popovercontroller.
if (popoverController) {
[popoverController setContentViewController:theMasterViewController
animated:NO];
}
当您的 UISplitViewControllerDelegate 被告知弹出框控制器将呈现视图控制器时,您还必须设置弹出框的 contentViewController:
- (void)splitViewController:(UISplitViewController*)svc
popoverController:(UIPopoverController*)pc
willPresentViewController:(UIViewController *)aViewController
{
// set the popoverController property - as per Apple's sample code
self.popoverController = pc;
// THE LINE BELOW IS THE NEW LINE!
[popoverController setContentViewController:aViewController animated:NO];
是的,我知道上面的代码看起来很疯狂,你想知道为什么苹果不能自己设置内容视图控制器。但他们显然没有,这就是解决方法。
更新
上面的方案,通过设置内容视图,结果证明是行不通的。例如,如果您将内容视图设置为 uinavigationcontroller,稍后您将通过导航控制器内部的根视图,而不是导航控制器本身。据我所知,UISplitViewController 只是不处理以任何可行的方式更改主视图。
我目前的解决方法是安装 UINavigationController 作为主视图,并更改该导航控制器的根视图控制器。所以我可以在某种程度上改变“后门”的主视图。
更新 2
我放弃。上面第一次更新中的方法也有缺陷;我在轮换时仍然遇到问题。基本上,如果您使用 UISplitViewController,您似乎不应该尝试对主视图控制器进行任何更改(即使您在主视图(例如作为弹出框)再次隐藏时切换主视图)。在主视图中摆弄 UINavigationController 的内容(当主视图显示时)看起来会没问题,但除此之外的任何事情都会导致问题接踵而至。
技术说明:我认为问题源于 Apple 处理 UI 的一个明显弱点:即,一旦隐藏或从视图中删除,Apple 代码将在 UIViews 和控制器上调用 release,但稍后,如果再次显示包含的视图控制器,则发送延迟消息,如 viewDidDisappear 到已发布的视图/控制器(此时可能已被释放)。