ios - 为什么 Swift ARC 不首先中断属性引用以防止保留循环?

标签 ios swift automatic-ref-counting retain-cycle

我只是想知道当代码块超出范围时 ARC 是如何工作的。我假设所有引用变量都设置为 nil/destroyed,排除了属性,并且所有引用计数为 0 的对象都被销毁。 这种情况:

A = nil
B = nil

或者也许所有变量和属性引用从上到下都设置为 nil,这将保留任何保留周期,因为在访问属性之前 A 和 B 为 nil。

A = nil
B = nil
A?.macbook = nil
B?.person = nil

所以我只是想知道为什么 ARC 不首先循环遍历属性(向后遍历代码)以首先删除属性引用,这会破坏任何保留周期。

    A?.macbook = nil
    B?.person = nil
    A = nil
    B = nil

我想我了解保留周期的基础知识,我只是好奇 ARC 在自动销毁阶段(例如完成函数的执行。也许属性引用未被访问/销毁,因为它们是对象的一部分?也许计算起来太复杂而无法检查每个属性?

       var name: String
       init(name: String) {
           self.name = name
           print("The Person \(name) is born")
       }
       var macbook: Macbook?
       deinit {
           print("The Person \(name) has died")
       }
   }
   
   class Macbook {
       var model: String
       init(model: String) {
           self.model = model
           print("The \(model) Macbook is born")
       }
       var person: Person?
       deinit {
           print("The \(model) Macbook has expired")
       }
   }
   
   func runTasks() {
       var A: Person? = Person(name: "Reuben")
       var B: Macbook? = Macbook(model: "Pro 2020")
       
       //Setup Retain Cycle
       A?.macbook = B
       B?.person = A
       
       //A?.macbook = nil
       B?.person = nil //**Why doesn't ARC make this nil first to avoid retain cycles?**
       A = nil
       B = nil
   }
   
   runTasks()

最佳答案

你问:

I'm just curious about the detail of what happens with ARC during an automated destruction phase e.g. finishing the execution of a function.

当您有一个引用对象实例的局部变量时,它会建立对该对象的强引用。当局部变量超出范围时,它会释放其强引用。如果这是对该对象的最后一个强引用,则该对象将被释放。

func runTasks() {
    var person = Person(name: "Reuben")
    
    // At this point, the `Person` object has one strong reference, as does the `MacBook`

    doSomething(with: person)

    // The `person` variable falls out of scope, the sole strong reference to the `Person` 
    // instance will be relieved, and the `Person` object will therefore be deallocated.
}

Perhaps properties references aren't accessed/destroyed because they are part of the object?

当一个对象被释放时,它的任何对其他对象具有强引用的属性也会自动释放。

func runTasks() {
    var person = Person(name: "Reuben")
    var computer = Macbook(model: "Pro 2020")
    
    // At this point, the `Person` object has one strong reference, as does the `MacBook`

    person.macbook = computer

    // Now the `Macbook` instance has two strong references, the local variable and the `Person`

    doSomething(with: person)

    // When `person` and `computer` variables the local variables fall out of scope
    // at the end of this function, their respective strong references to the `Person` 
    // and the `Macbook` objects will be released. But since there are no more strong
    // references to `Person`, it will be deallocated. But when it is deallocated,
    // its strong reference to `Macbook` will be released automatically, too. So now,
    // the two strong references to that `Macbook` object are now released, too (both
    // the `computer` local variable and the `macbook` property of `Person`), so it will
    // deallocated, too.
}

现在,正如您所确定的,强引用循环(以前称为“保留循环”)是指两个或多个对象相互保持强引用(因此,除非您手动nil这些引用中的一个或多个,它们最终会产生相互之间挥之不去的强引用,因此在循环被打破之前,它们都不会被释放)。

内存管理系统在运行时为我们识别并打破这些强引用循环似乎很有吸引力,但这在计算上是不切实际的。它必须构建一个内存图,识别哪些对象正在相互引用,并以某种方式找出要中断的引用。甚至在某些情况下,我们可能有一些短暂的周期,我们绝对不希望操作系统为我们解决(例如,您创建一个调度队列,调度一些工作 block ,并且我们依赖队列不会被释放,直到分派(dispatch)的 block 已完成;URLSession 是另一个示例)。

幸运的是,虽然这种恒定内存图分析在运行时不可行,但 Xcode 确实提供了一个调试工具来帮助识别这些场景,即“调试内存图”feature 。欲了解更多信息,请参阅How to debug memory leaks when Leaks instrument does not show them?How can identify strong reference cycles in Swift?iOS app with ARC, find who is owner of an object .

幸运的是,虽然我们有出色的诊断工具来查找这些强引用循环,但首先通过使用weakunowned打破循环来防止它们非常容易引用。结果是一个高性能、非常简单的内存管理基础设施,可以通过weak/unowned轻松避免循环,但我们有一些出色的调试工具,可以在需要时识别问题.

关于ios - 为什么 Swift ARC 不首先中断属性引用以防止保留循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64963072/

相关文章:

ios - 删除除最后一个以外的所有事件

objective-c - 用于 iOS ARC 问题的 BWDB SQLite 包装器

objective-c - 如何在ARC下自动释放未返回的对象

objective-c - 如何在 View 上放置 "x"个对象

ios - Apple 推荐的 Swift 日志记录方法

ios - uinavigationbar中的下拉菜单

ios - 如何在 TabBarController 加载其 View 后添加另一个 TabBarItem

ios - 应用程序终止时执行后台任务

ios - 创建自定义模糊 UIView

objective-c - 在 objective-c 中同时使用垃圾收集器和 ARC