ARC weak var Swift(不是闭包)

ARC weak var Swift (not closures)

我正在努力更好地理解 ARC 并正在使用 Apples Documentation

通过第一个示例,我没有得到 Apple 声明的预期结果; "Because a weak reference does not keep a strong hold on the instance it refers to, it’s possible for that instance to be deallocated while the weak reference is still referring to it. Therefore, ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated."

我在 XCode 8.3.2

中使用 playground
import UIKit

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}


var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil //This prints "John Appleseed is being deinitialized" (as expected)
unit4a?.tenant?.name //This shows "John Appleseed" (expected nil)
unit4a = nil //Prints "Unit4a is being deinitialized" (as expected)

我知道这会阻止强引用循环,因此两者都可以被取消初始化,但我不明白为什么 unit4a 保留对租户的引用?

您被右侧 playgrounds 的输出所欺骗,它与您的印刷品(如 deinits 中)的时间顺序不同。如果将独立 "echoes" 替换为实际的打印调用,您将在控制台中看到租户在您打印 unit4a?.tenant?.name 之后而不是之前被释放。这是因为弱对象的释放不会立即发生,而是在下一个 运行 循环中发生。 导入 UIKit 导入 XCPlayground

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}


var john: Person?
var unit4a: Apartment?

john = Person(name: "John Appleseed")
unit4a = Apartment(unit: "4A")

john!.apartment = unit4a
unit4a!.tenant = john

john = nil
print(unit4a?.tenant?.name)
unit4a = nil

输出:

Optional("John Appleseed")
John Appleseed is being deinitialized
Apartment 4A is being deinitialized

如果您将最后一位更改为:

john = nil

DispatchQueue.main.asyncAfter(deadline: .now()) {
    print(unit4a?.tenant?.name) //This shows "John Appleseed" (expected nil)
    unit4a = nil //Prints "Unit4a is being deinitialized" (as expected)
}

输出是你所期望的:

John Appleseed is being deinitialized
nil
Apartment 4A is being deinitialized

在大多数情况下,您不会在意对象是否会立即释放,但如果您在意,请查看自动释放池