【问题标题】:Is UIView superview property weak or strong?UIView superview 属性是弱还是强?
【发布时间】:2016-12-14 11:39:11
【问题描述】:

UIView 标头表明 superview 属性很强大

open var superview: UIView? { get }

但它的行为就像一个弱属性,即如果我创建 view1 和 view2,然后调用 view1.addSubview(view2),然后只将强 ref 保存到 view2(而不是 view1),即使 view1 也会被取消view2 通过其 superview 属性引用它。

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

编辑:例如,此代码打印“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)
    }
}

【问题讨论】:

  • 我无法重现该行为。你能发布最少的测试代码吗?

标签: ios xcode uiview uikit superview


【解决方案1】:

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

open var superview: UIView? { get }

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

即使它有一个 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;
}

【讨论】:

  • 这留下了关于如何存储超级层和层委托属性的问题……答案是CALayerGetSuperlayerCALayerGetDelegate 都使用objc_read_weak,所以超级视图实际上是间接归零- 弱属性。
  • 有趣的是,如果图层有不同的委托,那么超级视图方法会中断
【解决方案2】:

superview 属性不一定是强属性,可以是其他私有弱属性的计算属性。

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

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

p>

【讨论】:

    【解决方案3】:

    UIView 标头表明 superview 属性很强大

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-25
      • 1970-01-01
      • 2023-03-22
      • 2014-03-29
      • 2010-10-05
      • 1970-01-01
      • 2013-05-03
      • 2014-08-06
      相关资源
      最近更新 更多