在调用UIDynamicBehavior的动作关闭后,为什么会有内存泄漏/保留周期?

时间:2019-02-02 14:15:06

标签: swift memory-leaks uikit-dynamics uidynamicbehavior

此处的代码的想法是,当视图self.mv在屏幕上被UIDynamicAnimator动画化时,将其删除。

下面的代码基于Matt Neuburg撰写的《 Programming iOS 12 》第4章中的示例。作者说,行为和视图(代码中的self.mv)都不会被取消分配。但是他没有对此进行详尽的阐述。

我的问题是:

  1. self.anim.removeAllBehaviors()之后谁仍然保留该行为?

  2. 谁仍然保留self.mv

我使用了乐器,但是我不太理解输出。这是否意味着动画师保留了它?但是只有绿色的复选标记。

Instruments screen shot

使用XCode中的“调试内存图”工具,即使调用UIGravityBehavior之后,动画师仍会保留self.anim.removeAllBehaviors()

Debug Memory Graph

class MyView : UIView {
    deinit {
        print("dddddddd")
    }
}

class ViewController: UIViewController {

    var anim : UIDynamicAnimator!

    weak var mv : MyView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let v = MyView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))

        v.backgroundColor = .red

        self.view.addSubview(v)

        self.mv = v

        let grav = UIGravityBehavior()

        self.anim = UIDynamicAnimator(referenceView: self.view)

        self.anim.addBehavior(grav)
        grav.action = {
            let items = self.anim.views(in: self.view.bounds)

            let idx = items.firstIndex(of: self.mv!)

            if idx == nil {
                self.anim.removeAllBehaviors()
                self.mv!.removeFromSuperview()
                // self.anim = nil // without this, the `MyView` is not deallocated.
            }
        }

        grav.addItem(v)

    }
}

2 个答案:

答案 0 :(得分:2)

您有:

var anim : UIDynamicAnimator!

如果成功的话:

var anim : UIDynamicAnimator?

,并在动画制作完成后在回调中nil if idx == nil { self.anim?.removeAllBehaviors() self.mv!.removeFromSuperview() self.anim = nil // without this, the `MyView` is not deallocated. } ,这样可以解决您的额外保留问题:

entry

答案 1 :(得分:0)

self拥有拥有重力的动画,而grav拥有保留自我的动作块。

这是一个保留循环,所以自的引用计数将永远不会被递减到零,所以自会泄漏。

您需要做弱者舞蹈来解决此问题。

{[weak self] in
  if let strongSelf = self {
    let items = strongSelf.anim.views(in: strongSelf.view.bounds)
    ...