环境
iOS 9.2
Xcode 7.2
我希望用动画替换UIWindow's rootViewController,同时也将其从视图层次结构中删除。
* {
margin: 0;
padding: 0;
}
#header {
position: fixed;
top: 0;
left: 0;
min-width: 320px;
max-width: 100%;
width: 100%;
height: 100%;
background: url("http://placehold.it/960x290") no-repeat top center;
}
#main {
position: relative;
font-family: 'Hind', sans-serif;
color: black;
text-align: center;
font-size: 2.5vw;
background-color: transparent;
padding-top: 50vh; /* for test purposes only */
height: 100vh; /* for test purposes only */
}
然后只需通过
启动AppDelegate中的转换<div id="header">
</div>
<div id="main">
<table>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
</table>
</div>
在Instruments中对此进行分析,请注意rootViewController仍在内存中。
还遇到了这个bug report,这似乎表明iOS 8.3中存在同样的问题,但仍然是开放的。
Haven能够找到任何建议,作为
的一部分class FooViewController: UIViewController
{
}
class LeakedViewController: UIViewController
{
}
保留source view controller(最有可能是UIPresentationController?)或者这是一个错误。请注意,UIPresentationController最初是在iOS 8中引入的。
如果是设计,是否有选项来释放源视图控制器?
使用UIPresentationController的子类
self.window!.rootViewController = LeakedViewController()
let fooViewController = FooViewController()
self.window!.rootViewController?.presentViewController(fooViewController, animated: true){ unowned let window = self.window!
window.rootViewController = fooViewController
}
似乎没有任何区别。 Haven无法在SDK中找到任何其他内容。
目前,我找到的唯一方法是使用UIViewController,其中包含当前屏幕上的内容的快照,代替根视图控制器,然后再进行转换。
UIViewController.presentViewController(animated:completion:)
它确实有效,在控制台中出现以下警告
override func shouldPresentInFullscreen() -> Bool {
return true
}
override func shouldRemovePresentersView() -> Bool {
return true
}
对原始问题或警告信息的任何想法都表示赞赏。
更新
我相信我已经把它缩小到了这个保留错过了一个版本。
这是可能违规的电话。
let fooViewController = FooViewController()
let view = self.window!.snapshotViewAfterScreenUpdates(false)
let viewController = UIViewController()
viewController.view.addSubview(view)
self.window!.rootViewController = viewController
self.window!.rootViewController?.presentViewController(dashboardViewController!, animated: true){ unowned let window = self.window!
window.rootViewController = fooViewController
}
答案 0 :(得分:4)
我记录了该错误报告;我对Apple工程没有回应。
我提交的示例代码以及显示问题的错误报告位于https://github.com/adurdin/radr21404408
据我所知,这个问题仍然存在于当前版本的iOS中,但我还没有详尽地测试过。谁知道,也许9.3 beta修复了吗? :)
在我遇到此错误的应用程序中,我们一直在使用自定义转换和rootViewController替换大多数屏幕转换。我还没有找到这种泄漏的解决方案,并且由于原因无法轻易删除所有的rootViewController操作,因此通过最小化我们使用presentViewController和朋友的位置来解决问题,并仔细管理我们需要它的地方。
我认为有一种方法可以避免这个错误,同时仍然保留与rootViewController交换相似的功能 - 但尚未实现 - 是让rootViewController成为占用整个屏幕的自定义容器视图控制器,并定义演示文稿上下文。我不会交换窗口的rootViewController,而是在这个容器中交换单个子视图控制器。并且因为容器定义了表示上下文,所以演示将从容器而不是交换子进行。这应该可以避免泄漏。
答案 1 :(得分:4)
受@Jordan Smiths的启发评论我的解决方案以一个班轮结束(感谢Swift的美丽):
window.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
将rootViewController与动画交换的完整代码如下所示:
func swapRootViewController(newController: UIViewController) {
if let window = self.window {
window.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
UIView.transitionWithView(window, duration: 0.3, options: .TransitionCrossDissolve, animations: {
window.rootViewController = newController
}, completion: nil)
}
}
随着我的记忆泄漏消失了: - )
答案 2 :(得分:0)
问题可能是所呈现的控制器和呈现视图控制器相互引用。
我只能通过实例化转换到视图控制器的两个副本来实现此功能。一个用于呈现当前根,一个用于在呈现后替换当前根。这些副本很容易实现,因为所呈现的VC是简单的对象。解雇后,呈现的视图将保留在窗口层次结构中,因此必须在交换新VC后手动删除。
这是一些Swift。
private func present(_ presented: UIViewController, whenPresentedReplaceBy replaced: @escaping () -> UIViewController)
{
presented.modalTransitionStyle = .crossDissolve
let currentRoot = self.window?.rootViewController
currentRoot?.present(presented, animated: true)
{
let nextRoot = replaced()
self.window?.rootViewController = nextRoot
currentRoot?.dismiss(animated: false) {
currentRoot?.view?.removeFromSuperview()
}
}
}