未引用的对象是否可能保留在内存中并调用目标操作?

Is it possible for an unreferenced object to stay in memory and invoke target action?

我有一个 class 这样的:

class Example: UIView {
    init(frame: CGRect) {
        super.init(frame: frame); 
        let tap = UITapGestureRecognizer(target: self, action: #selector(dismiss(_:)));
        self.addGestureRecognizer(tap)
        self.isUserInteractionEnabled = true;
        self.backgroundColor = UIColor.red;
    }
    func show(parentView: UIView) { 
        parentView.addSubview(self);
    }
    @objc func dismiss(_ sender: UITapGestureRecognizer? = nil) {
        self.removeFromSuperview();
    }
}

然后我想这样称呼它:

override func viewWillAppear() {
    super.viewWillAppear();
    Example.init(frame: self.view.bounds).show(parentView: self.view);
}

视图按预期显示为红色背景。但是当我点击视图时,什么也没有发生。甚至没有调用 dismiss 函数。

但是如果这样做的话:

var example : UIView!;
override func viewWillAppear() {
    super.viewWillAppear();
    example = Example.init(frame: self.view.bounds);
    example.show(parentView: self.view);
}

水龙头工作正常。我怀疑这是因为该物体在途中被破坏了?但它仍然存在于 UIView 子视图堆栈中?我认为它没有被完全破坏,因为它被父视图子视图引用了,对吗?我可以在不创建局部变量来保存对象(仅由子视图引用)的情况下使目标操作起作用吗?

您不需要为 Example 的实例创建 ivar。通过调用 show(parent:) 你最终将它添加到视图层次结构中,视图层次结构保留了它。所以它留在记忆中。

如果我 运行 在一个全新的 Xcode 单视图应用程序项目中使用您的示例代码,它在没有 ivar 的情况下也能正常工作。我的代码是:

import UIKit

class Example: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame);
        let tap = UITapGestureRecognizer(target: self, action: #selector(dismiss(_:)));
        self.addGestureRecognizer(tap)
        self.isUserInteractionEnabled = true;
        self.backgroundColor = UIColor.red;
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func show(parentView: UIView) {
        parentView.addSubview(self);
    }
    @objc func dismiss(_ sender: UITapGestureRecognizer? = nil) {
        self.removeFromSuperview();
    }
}

class ViewController: UIViewController {

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        Example.init(frame: self.view.bounds).show(parentView: self.view);
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

当我 运行 这段代码时会发生什么:

因此,点击红色 Example 视图似乎使其消失,就像您希望的那样。

是的,这是可行的,因为父视图始终是其子视图的所有者。如果不是这样,您 iPhone 上的大多数屏幕都会非常空旷,因为它们没有所有者。为此,outlets使用弱引用也是可以的。