在使用转换时替换 UIWindow 的 rootViewController,似乎正在泄漏
Replacing the UIWindow's rootViewController while using a transition, appears to be leaking
环境
iOS9.2
Xcode7.2
我希望用动画替换 UIWindow's rootViewController,同时也将其从视图层次结构中删除。
class FooViewController: UIViewController
{
}
class LeakedViewController: UIViewController
{
}
然后通过
在 AppDelegate 中启动转换
self.window!.rootViewController = LeakedViewController()
let fooViewController = FooViewController()
self.window!.rootViewController?.presentViewController(fooViewController, animated: true){ unowned let window = self.window!
window.rootViewController = fooViewController
}
在 Instruments 中对此进行分析,注意 rootViewController 仍在内存中。
也遇到了这个 bug report 这似乎表明 iOS 8.3 中存在同样的问题并且仍然开放。
无法找到任何参考资料来表明作为
的一部分
UIViewController.presentViewController(animated:completion:)
source view controller is retained (most likely by the UIPresentationController?) 或者这是一个错误。请注意 UIPresentationController 是在 iOS 8.
中首次引入的
如果这是设计使然,是否有发布源代码视图控制器的选项?
使用 UIPresentationController 的子类
override func shouldPresentInFullscreen() -> Bool {
return true
}
override func shouldRemovePresentersView() -> Bool {
return true
}
似乎没有任何区别。无法在 SDK 中找到任何其他内容。
目前我找到的唯一方法是使用 UIViewController,在进行转换之前使用屏幕上当前内容的快照代替根视图控制器。
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
}
它确实有效,但在控制台中出现以下警告
Unbalanced calls to begin/end appearance transitions for <UIViewController: 0x79d991f0>.
对原始问题或警告消息的任何想法表示赞赏。
更新
我相信我已经将范围缩小到这个缺少版本的保留。
这可能是个冒犯性的电话。
0 UIKit -[UIPresentationController _presentWithAnimationController:interactionController:target:didEndSelector:]
我记录了那个错误报告;我没有收到 Apple 工程师的回复。
我随错误报告一起提交的演示该问题的示例代码位于 https://github.com/adurdin/radr21404408
据我所知,这个问题在 iOS 的当前版本中仍然存在,但我没有进行详尽的测试。谁知道,也许 9.3 beta 修复了它? :)
在我遇到这个错误的应用程序中,我们一直在使用自定义转换和 rootViewController 替换大多数屏幕转换。我还没有找到解决此泄漏的方法,并且由于某些原因无法轻松删除所有 rootViewController 操作,因此通过最小化我们使用 presentViewController 和朋友的地方并仔细管理我们需要它的地方来解决这个问题。
我认为有可能避免该错误同时仍保留与 rootViewController 交换类似功能(但尚未实施)的一种方法是让 rootViewController 成为占据全屏的自定义容器视图控制器,并定义了一个表示上下文。我不会交换 window 的 rootViewController,而是交换此容器中的单个 child 视图控制器。而且因为容器定义了表示上下文,所以表示将从容器而不是 child 被交换。这样应该可以避免泄漏。
受@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)
}
}
这样我的内存泄漏就消失了:-)
问题可能是呈现的控制器和呈现的视图控制器相互引用。
我只能通过实例化转换到视图控制器的两个副本来让它工作。一种用于在当前根上呈现,另一种用于在呈现后替换当前根。这些副本对我来说很容易实现,因为呈现的 VC 是简单的对象。呈现的视图在关闭后留在 window 层次结构中,因此必须在交换新的 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()
}
}
}
环境
iOS9.2
Xcode7.2
我希望用动画替换 UIWindow's rootViewController,同时也将其从视图层次结构中删除。
class FooViewController: UIViewController
{
}
class LeakedViewController: UIViewController
{
}
然后通过
在 AppDelegate 中启动转换 self.window!.rootViewController = LeakedViewController()
let fooViewController = FooViewController()
self.window!.rootViewController?.presentViewController(fooViewController, animated: true){ unowned let window = self.window!
window.rootViewController = fooViewController
}
在 Instruments 中对此进行分析,注意 rootViewController 仍在内存中。
也遇到了这个 bug report 这似乎表明 iOS 8.3 中存在同样的问题并且仍然开放。
无法找到任何参考资料来表明作为
的一部分UIViewController.presentViewController(animated:completion:)
source view controller is retained (most likely by the UIPresentationController?) 或者这是一个错误。请注意 UIPresentationController 是在 iOS 8.
中首次引入的如果这是设计使然,是否有发布源代码视图控制器的选项?
使用 UIPresentationController 的子类
override func shouldPresentInFullscreen() -> Bool {
return true
}
override func shouldRemovePresentersView() -> Bool {
return true
}
似乎没有任何区别。无法在 SDK 中找到任何其他内容。
目前我找到的唯一方法是使用 UIViewController,在进行转换之前使用屏幕上当前内容的快照代替根视图控制器。
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
}
它确实有效,但在控制台中出现以下警告
Unbalanced calls to begin/end appearance transitions for <UIViewController: 0x79d991f0>.
对原始问题或警告消息的任何想法表示赞赏。
更新
我相信我已经将范围缩小到这个缺少版本的保留。
这可能是个冒犯性的电话。
0 UIKit -[UIPresentationController _presentWithAnimationController:interactionController:target:didEndSelector:]
我记录了那个错误报告;我没有收到 Apple 工程师的回复。
我随错误报告一起提交的演示该问题的示例代码位于 https://github.com/adurdin/radr21404408
据我所知,这个问题在 iOS 的当前版本中仍然存在,但我没有进行详尽的测试。谁知道,也许 9.3 beta 修复了它? :)
在我遇到这个错误的应用程序中,我们一直在使用自定义转换和 rootViewController 替换大多数屏幕转换。我还没有找到解决此泄漏的方法,并且由于某些原因无法轻松删除所有 rootViewController 操作,因此通过最小化我们使用 presentViewController 和朋友的地方并仔细管理我们需要它的地方来解决这个问题。
我认为有可能避免该错误同时仍保留与 rootViewController 交换类似功能(但尚未实施)的一种方法是让 rootViewController 成为占据全屏的自定义容器视图控制器,并定义了一个表示上下文。我不会交换 window 的 rootViewController,而是交换此容器中的单个 child 视图控制器。而且因为容器定义了表示上下文,所以表示将从容器而不是 child 被交换。这样应该可以避免泄漏。
受@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)
}
}
这样我的内存泄漏就消失了:-)
问题可能是呈现的控制器和呈现的视图控制器相互引用。
我只能通过实例化转换到视图控制器的两个副本来让它工作。一种用于在当前根上呈现,另一种用于在呈现后替换当前根。这些副本对我来说很容易实现,因为呈现的 VC 是简单的对象。呈现的视图在关闭后留在 window 层次结构中,因此必须在交换新的 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()
}
}
}