此视图控制器是否在"willSet/didSet"中泄漏?一对? [英] Does this view controller leak in a "willSet/didSet" pair?

查看:74
本文介绍了此视图控制器是否在"willSet/didSet"中泄漏?一对?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您有一个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实际上是错误的.但是,最大的问题是您试图在willSetdidSet之间拆分代码,因为根本不需要这样做.您随时可以在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)
    }
}

顺便说一句,函数的调用顺序很重要.因此,我不建议将功能分为removeadd.否则,两个控制器的viewDidDisappearviewDidAppear的顺序可能会令人惊讶.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆