此视图控制器是否在"willSet/didSet"中泄漏?一对? [英] Does this view controller leak in a "willSet/didSet" pair?
问题描述
您有一个vc(绿色),并且有一个面板(黄色)持有人"
You have a vc (green) and it has a panel (yellow) "holder"
假设您有十种不同的视图控制器...价格,销售,库存,卡车,驾驶员,调色板,您将一次将它们放在黄色区域中.它将从情节提要中动态加载每个VC
Say you have ten different view controllers...Prices, Sales, Stock, Trucks, Drivers, Palettes, which you are going to put in the yellow area, one at a time. It will dynamically load each VC from storyboard
instantiateViewController(withIdentifier: "PricesID") as! Prices
我们将当前的VC保留在current
中.这是允许您在它们之间交换"的代码.
We will hold the current VC one in current
. Here's code that will allow you to "swap between" them...
一个人必须做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)
}
}
}
>>>>>>>>>>重要!
还请注意,如果您执行这样的操作,则在完成绿色页面后,必须摆脱黄色视图控制器.否则current
将保留它,并且永远不会释放绿色页面:
>>>>>>>>IMPORTANT!<<<<<<<<<
Also note, if you do something like this, it is ESSENTIAL to get rid of the yellow view controller when the green page is done. Otherwise current
will retain it and the green page will never be released:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
current = nil
super.dismiss(animated: flag, completion: completion)
}
继续,您将使用current
属性,如下所示:
Continuing, you'd use the current
property like this:
func showPrices() {
current = s.instantiateViewController(withIdentifier: "PricesID") as! Prices
}
func showSales() {
current = s.instantiateViewController(withIdentifier: "SalesID") as! Sales
}
但是请考虑一下,注意"X点" .通常,您一定要将要摆脱的视图控制器设置为nil.
But consider this, notice "point X". Normally there you'd be sure to set the view controller you are getting rid of to nil.
blah this, blah that
blah.removeFromParentViewController()
blah = nil
但是,我(不认为)您可以在"willSet"代码块中真正将current设置为nil.而且,我很感激它即将被设置为某些东西(在didSet中).但这似乎有些奇怪.少了什么东西?您甚至可以在计算属性中执行这种操作吗?
However I (don't think) you can really set current to nil inside the "willSet" code block. And I appreciate it's just about to be set to something (in didSet). But it seems a bit strange. What's missing? Can you even do this sort of thing in a computed property?
使用Sulthan的方法,经过大量测试后,此方法才能完美运行.
Using Sulthan's approach, this then works perfectly after considerable testing.
所以这样叫
// 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)
}
推荐答案
我不认为使用didSet
实际上是错误的.但是,最大的问题是您试图在willSet
和didSet
之间拆分代码,因为根本不需要这样做.您随时可以在didSet
中使用oldValue
:
I don't think that using didSet
is actually wrong. However, the biggest problem is that you are trying to split the code between willSet
and didSet
because that's not needed at all. You can always use oldValue
in didSet
:
var current: UIViewController? = nil {
didSet {
guard current != oldValue else {
return
}
oldValue?.willMove(toParentViewController: nil)
if let current = current {
self.addChildViewController(current)
}
//... add current.view to the view hierarchy here...
oldValue?.view.removeFromSuperview()
oldValue?.removeFromParentViewController()
current?.didMove(toParentViewController: self)
}
}
顺便说一句,函数的调用顺序很重要.因此,我不建议将功能分为remove
和add
.否则,两个控制器的viewDidDisappear
和viewDidAppear
的顺序可能会令人惊讶.
By the way, the order in which the functions are called is important. Therefore I don't advise to split the functionality into remove
and add
. Otherwise the order of viewDidDisappear
and viewDidAppear
for both controllers can be surprising.
这篇关于此视图控制器是否在"willSet/didSet"中泄漏?一对?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!