你有一个 vc(绿色),它有一个面板(黄色)“holder”
假设您有十个不同的 View Controller ...价格、销售、库存、卡车、司机、调色板,您将把它们一次一个地放在黄色区域。它会从 Storyboard中动态加载每个 VC
instantiateViewController(withIdentifier: "PricesID") as! Prices
我们将在 current
中保留当前的 VC。这是允许您在它们之间“交换”的代码...
>>注意,这是错误的。不要使用此代码<<
必须按照 Sulthan 在下面解释的方法进行操作。
var current: UIViewController? = nil {
willSet {
// recall that the property name ("current") means the "old" one in willSet
if (current != nil) {
current!.willMove(toParentViewController: nil)
current!.view.removeFromSuperview()
current!.removeFromParentViewController()
// "!! point X !!"
}
}
didSet {
// recall that the property name ("current") means the "new" one in didSet
if (current != nil) {
current!.willMove(toParentViewController: self)
holder.addSubview(current!.view)
current!.view.bindEdgesToSuperview()
current!.didMove(toParentViewController: self)
}
}
}
>>>>>>>>重要!<<<<<<<<<
另请注意,如果您执行此类操作,则必须在完成绿色页面后摆脱黄色 View Controller 。否则 current
将保留它并且永远不会释放绿页:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
current = nil
super.dismiss(animated: flag, completion: completion)
}
继续,您将像这样使用 current
属性:
func showPrices() {
current = s.instantiateViewController(withIdentifier: "PricesID") as! Prices
}
func showSales() {
current = s.instantiateViewController(withIdentifier: "SalesID") as! Sales
}
但考虑到这一点,请注意“X 点”。通常,您一定要将要删除的 View Controller 设置为 nil。
blah this, blah that
blah.removeFromParentViewController()
blah = nil
但是我(不认为)您真的可以在“willSet”代码块中将 current 设置为 nil。我很高兴它即将被设置为某些东西(在 didSet 中)。但这似乎有点奇怪。少了什么东西?您甚至可以在计算属性中执行此类操作吗?
最终可用版本......
使用 Sulthan 的方法,经过相当多的测试后,这可以完美地工作。
这样调用
// change yellow area to "Prices"
current = s.instantiateViewController(withIdentifier: "PricesID") as! Prices
// change yellow area to "Stock"
current = s.instantiateViewController(withIdentifier: "StickID") as! Stock
这很好用...
var current: UIViewController? = nil { // ESSENTIAL to nil on dismiss
didSet {
guard current != oldValue else { return }
oldValue?.willMove(toParentViewController: nil)
if (current != nil) {
addChildViewController(current!)
holder.addSubview(current!.view)
current!.view.bindEdgesToSuperview()
}
oldValue?.view.removeFromSuperview()
oldValue?.removeFromParentViewController()
if (current != nil) {
current!.didMove(toParentViewController: self)
}
}
// courtesy http://stackoverflow.com/a/41900263/294884
}
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
// ESSENTIAL to nil on dismiss
current = nil
super.dismiss(animated: flag, completion: completion)
}
最佳答案
我们把问题分成两个:(1)有没有“漏”? (2) 这是个好主意吗?
首先是“泄漏”。简短的回答:没有。即使你不将current
设置为nil
,它持有的view controller显然不会“泄露”;当包含的 View Controller 不复存在时,current
指向的 View Controller 也不复存在。
但是,current
view controller 的生命周期比它需要的要长。因此,这似乎是一件愚蠢的事情。不需要对 subview Controller 的强引用current
,因为它毕竟是你的childViewControllers[0]
(如果你做 subview Controller “正确地跳舞)。因此,您只是用您的属性复制 childViewControllers
属性已经所做的事情。
那么这就引出了第二个问题:您的做法是个好主意吗?不,我知道你来自哪里——你想封装 subview Controller 的“舞蹈”。但是无论如何你都在错误地跳舞;你因此颠覆了 View Controller 层次结构。为了封装“舞蹈”,我会说你最好正确地完成舞蹈并提供执行它的函数,以及一个计算的只读属性,它引用到 childViewController[0]
(如果存在)。
在这里,我假设我们一次只有一个 subview Controller ;我认为这比您尝试做的事情要好得多:
var current : UIViewController? {
if self.childViewControllers.count > 0 {
return self.childViewControllers[0]
}
return nil
}
func removeChild() {
if let vc = self.current {
vc.willMove(toParentViewController: nil)
vc.view.removeFromSuperview()
vc.removeFromParentViewController()
}
}
func createChild(_ vc:UIViewController) {
self.removeChild() // There Can Be Only One
self.addChildViewController(vc) // *
// ... get vc's view into the interface ...
vc.didMove(toParentViewController: self)
}
关于swift - 这个 View Controller 是否在 "willSet/didSet"对中泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41898476/