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"。你所知道的是,你可以通过 属性 语法请求超级视图,你会被告知它是什么。未指定幕后如何完成,您不应该关心它。
话虽如此:显然一个视图对其父视图没有强引用,因为如果它这样做,就会有一个保留周期(因为一个父视图拥有它的子视图,因此对它有一个强引用)。
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"。你所知道的是,你可以通过 属性 语法请求超级视图,你会被告知它是什么。未指定幕后如何完成,您不应该关心它。
话虽如此:显然一个视图对其父视图没有强引用,因为如果它这样做,就会有一个保留周期(因为一个父视图拥有它的子视图,因此对它有一个强引用)。