知道什么时候弱变量在Swift中变为零?

时间:2022-11-02 16:52:57

Let's say I have a weak var view: UIView? in my class Button {}. Is there any way to know when view loses its reference and becomes nil?

假设我有一个弱的var视图:UIView?在我的班级按钮{}。是否有任何方法可以知道何时视图丢失其参考并变为零?

I tried using weak var view: UIView? {} (aka a computed property) in order to override set {}, but that didn't work because now it's a computed property and can't store a weak reference (how annoying!).

我尝试使用弱var视图:UIView? {}(也称为计算属性)为了覆盖set {},但这不起作用,因为现在它是一个计算属性,不能存储弱引用(多么烦人!)。

Edit:

编辑:

@fqdn's answer didn't work with this code... Try it in an Xcode Playground

@ 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

Your output console should display:

您的输出控制台应显示:

target set to view
target set to nil

My console displays

我的控制台显示

target set to view

b.view is the strong reference for the UIView instance. t.target is the weak reference. Therefore, if b.view is set to nil, the UIView instance is deallocated and t.target will be equal to nil.

b.view是UIView实例的强引用。 t.target是弱参考。因此,如果b.view设置为nil,则取消分配UIView实例并且t.target将等于nil。

1 个解决方案

#1


12  

If your button is holding a reference to another view, it should either be an owner of that view (i.e., it should hold a strong reference) or it should not care when that view goes away (i.e., its weak reference to it becomes nil.) There is no notification when weak references become nil, and that is by design.

如果你的按钮持有对另一个视图的引用,它应该是该视图的所有者(即,它应该具有强引用)或者当该视图消失时它不应该关心(即,它对它的弱引用变为零) 。)当弱引用变为零时,没有通知,这是设计的。

In particular, Swift property observers are not called when weak references become nil, as the following code demonstrates:

特别是,当弱引用变为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()

When work() is called, the console gives the following output:

调用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

Notice that in neither case of the instance of A deallocating and its weak reference in the instance of B becoming nil are the property observers called. Only in the direct case of assignment to B.a are they called.

请注意,在A取消分配的实例和在B变为nil的实例中的弱引用都没有被调用的属性观察者。只有在分配给B.a的直接情况下才会调用它们。

#1


12  

If your button is holding a reference to another view, it should either be an owner of that view (i.e., it should hold a strong reference) or it should not care when that view goes away (i.e., its weak reference to it becomes nil.) There is no notification when weak references become nil, and that is by design.

如果你的按钮持有对另一个视图的引用,它应该是该视图的所有者(即,它应该具有强引用)或者当该视图消失时它不应该关心(即,它对它的弱引用变为零) 。)当弱引用变为零时,没有通知,这是设计的。

In particular, Swift property observers are not called when weak references become nil, as the following code demonstrates:

特别是,当弱引用变为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()

When work() is called, the console gives the following output:

调用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

Notice that in neither case of the instance of A deallocating and its weak reference in the instance of B becoming nil are the property observers called. Only in the direct case of assignment to B.a are they called.

请注意,在A取消分配的实例和在B变为nil的实例中的弱引用都没有被调用的属性观察者。只有在分配给B.a的直接情况下才会调用它们。