我们说weak var view: UIView?
中有一个class Button {}
。有没有办法知道view
何时失去参考并成为nil
?
我尝试使用weak var view: UIView? {}
(也称为计算属性)来覆盖set {}
,但这不起作用,因为现在它已成为计算属性而无法使用存储一个弱引用(多么烦人!)。
修改
@fqdn 的答案没有使用此代码...在Xcode Playground中试用
import UIKit
class Test {
weak var target: UIView? {
willSet {
if !newValue { println("target set to nil") }
else { println("target set to view") }
}
}
}
class Button {
var view: UIView? = UIView()
}
var t = Test()
var b = Button()
t.target = b.view
b.view = nil // t.target's willSet should be fired here
您的输出控制台应显示:
target set to view
target set to nil
我的控制台显示
target set to view
b.view
是UIView实例的强引用。 t.target
是弱参考。因此,如果b.view
设置为nil
,则取消分配UIView实例,t.target
将等于nil。
答案 0 :(得分:13)
如果你的按钮持有对另一个视图的引用,它应该是该视图的所有者(即,它应该具有强引用),或者当该视图消失时它不应该关心(即,它的弱引用它变为零。)当弱引用变为零时没有通知,这是设计的。
特别是,当弱引用变为nil时,不会调用Swift属性观察器,如下面的代码所示:
class A : CustomStringConvertible {
var s: String?
init(s: String) {
self.s = s;
print("\(self) init")
}
deinit {
print("\(self) deinit")
}
var description: String {
get { return "[A s:\(s ?? "nil")]" }
}
}
class B : CustomStringConvertible {
weak var a:A? {
willSet {
print("\(self) willSet a")
}
didSet {
print("\(self) didSet a")
}
}
init(a: A?) {
self.a = a
print("\(self) init")
}
deinit {
print("\(self) deinit")
}
var description: String {
get { return "[B a:\(a == nil ? "nil" : String(describing: a!))]" }
}
}
func work() {
var a: A? = A(s: "Hello")
var b = B(a: a)
print("\(b)")
a = nil
print("\(b)")
b.a = A(s: "Goodbye")
}
work()
调用work()
时,控制台会提供以下输出:
[A s:Hello] init
[B a:[A s:Hello]] init
[B a:[A s:Hello]]
[A s:Hello] deinit
[B a:nil]
[A s:Goodbye] init
[B a:nil] willSet a
[B a:[A s:Goodbye]] didSet a
[A s:Goodbye] deinit
[B a:nil] deinit
请注意,在A解除分配的实例和B的实例中的弱引用都不是n的情况下,属性观察者都会被调用。只有在分配给B.a的直接情况下才会被称为。