UIView superview 属性 弱还是强?

Is UIView superview property weak or strong?

UIView header 说明 superview 属性 很强

open var superview: UIView? { get }

但它的行为就像一个弱 属性,即如果我创建 view1 和 view2 然后调用 view1.addSubview(view2),然后仅将强引用保存到 view2(而不是 view1 ), view1 将被取消初始化,即使 view2 通过其父视图 属性.

引用它

所以,我想知道它在现实中是如何实现的。

Edit:例如,此代码打印 "deinit"(ViewController 实例显示在屏幕上),这意味着 view1 被取消,即使 view2 应该通过 superview 属性.

强烈持有它
class View: UIView {
    deinit {
        print("deinit")
    }
}

class ViewController: UIViewController {

    var view2 = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        let view1 = View()
        view1.addSubview(view2)
    }
}

超级视图 属性 不一定是强 属性 并且可以是其他私有弱 属性.

的计算 属性

addSubview 方法建立了从父视图到子视图的强引用,而不一定是从子视图到父视图。

在 viewDidLoad 方法结束时,view1 不在视图层次结构中,并且没有任何其他对象指向 view1,因此它被释放,但是 view2 也有指向它的视图控制器,因此 view2 没有被释放。

Oleg 的回答是正确的,但值得进一步深入研究。您正在查看此接口定义:

open var superview: UIView? { get }

你假设这意味着这是一个强大的属性。它根本没有这么说。它说 UIView 有一个只读 superview 属性。没有 setter,因此您不会期望任何内存管理注释 (strong/weak/unowned)。

即使它有一个 setter,例如 UIView.backgroundColor:

var backgroundColor: UIColor? { get set }

这完全没有告诉我们有关内存管理的任何信息。没有承诺这个 UIColor 将被视图保留。制作自己的副本是免费的。它可以从 UIColor 中免费提取信息并生成一些其他对象供其内部使用(如 CGColor),然后将其丢弃。没有承诺 backgroundColor 有支持 ivar。这是免费的计算 setter.

一些属性,如委托,被标记为 weak:

weak var transitioningDelegate: UIViewControllerTransitioningDelegate? { get set }

您通常可以相信这些不会保留传递的对象,但请记住这些是信息,而不是保证。考虑一下这完全合法(而且完全可怕)Swift:

class AnotherClass {
    deinit { print("deinit") }
}

class MyClass {
    private var _myProp: AnotherClass?
    weak var myProp: AnotherClass? {
        get { return _myProp }
        set { _myProp = newValue }
    }
}

myProp 声称是 weak 但实际上确实保留了它的价值。你永远不应该这样做,但关键是语言不会阻止你。

从这一切中得出的结论是,如果您关心某个对象是否继续存在,那么您有责任维护对该对象的强引用。当你不关心它是否存在时,你应该释放你对它的强引用。您应该避免依赖其他对象来为您维护它。

(在实践中,有很多实际情况,依赖于其他对象会为你保存一些东西这一事实非常方便。例如,我们当然严重依赖数组持有强引用这一事实到他们的内容。但是如果你需要它,你可以确定容器是否承诺这种行为。只看界面是不够的。)

对于UIView的具体问题,这是一个计算出来的属性。虽然是实现细节,但这里大致介绍了它在 iOS 10.1 中的实现方式:

- (UIView *)superview {
    UIView *result;
    if ([UIView _isAccessingModel] != 0x0) {
            id visualState = [self visualState];
            result = [visualState mSuperview];
    }
    else {
            if ([self viewFlags] & 0x400000)) {
                    CALayer *superLayer = CALayerGetSuperlayer([self layer]);
                    result = nil;
                    if (superlayer != nil) {
                            result = CALayerGetDelegate(layer);
                    }
            }
    }
    return result;
}

The UIView header states that superview property is strong

它根本没有说明这一点。它声明的是 属性 是 只读 。您不能 设置 超级视图,因此甚至不会出现保留策略问题。你甚至不知道有没有一个"superview reference"。你所知道的是,你可以通过 属性 语法请求超级视图,你会被告知它是什么。未指定幕后如何完成,您不应该关心它。

话虽如此:显然一个视图对其父视图没有强引用,因为如果它这样做,就会有一个保留周期(因为一个父视图拥有它的子视图,因此对它有一个强引用)。