ARC 及其具体工作原理。

sli*_*boy 2 memory-management ios automatic-ref-counting swift

我刚刚学习了 ARC 教程并获得了此代码。

下面是 ViewController 类,下面是 Vehicle 类。

我从中得到的是,ARC 本质上跟踪实例化的类并为其分配一块内存。当创建实例的“强”引用时,arc 会增加对该实例的引用数量的增量。一旦它们全部设置为 nil,ARC 就会从内存中释放该实例。讲师还说过,一旦所有引用都没有被使用,它就会从内存中释放。我不太明白它们没有被“使用”的部分,所以我决定添加一个按钮,该按钮显示另一个空白的视图控制器,没有代码。我想如果我导航到下一个视图控制器,deinit 将被调用,因为视图控制器 1 中的引用现在未被使用,因此从内存中释放。事实并非如此,并且 deinit 没有被调用。因此,我想知道,除非您始终将引用设置为 nil,否则引用是否会保留在内存中?

问题的第 2 部分:此外,当您回答这个问题时,我还有另一个问题,我还想知道 ARC 是否仅适用于类实例及其引用,因为我查找的每一篇文档或教程似乎都只适用于提及类实例。例如,如果我设置var number = 2 var othernumber = number,“number”是否也存储在内存中,并且只有在对它的所有引用为零之前才释放。如果也是这种情况,那么同样的问题也适用,将所有引用设置为 nil 是从内存中释放的唯一方法吗?抱歉问了这么长的问题,但我对内存概念还很陌生。

import UIKit

class ViewController: UIViewController {


var ref1: Vehicle?
var reference2: Vehicle?
var ref3: Vehicle?
var timer: NSTimer!
var count = 0
override func viewDidLoad() {
    super.viewDidLoad()

    ref1 = Vehicle(kind: "Car")
    reference2 = ref1
    ref3 = ref1

    timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(tick), userInfo: nil, repeats: true)


}


func tick() {
count++

    if count >= 3 {
        ref3 = nil
        reference2 = nil



    }

    if count == 5 {
    ref1 = nil


    }


}
Run Code Online (Sandbox Code Playgroud)

}

   class Vehicle {

let type: String


init(kind: String){
self.type = kind
print("\(type) is being initialized")
//when the class is instantiated, we get an initialization message. When class is deallocated, we get a deinit message. As in, all strong references are gone, we can deinitialize.


}
deinit {
//class vehicle not in memory anymore as all strong references to it have been destroyed. This will be tested with segue as well. 
    print("\(type) is being deinitialized")

}}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 5

  1. “使用的”术语令人困惑/误导(或者充其量是不精确)。使用ARC,直到没有剩余的强引用时才会释放对象,简单明了。如果nil所有这些强引用,或者那些强引用超出了范围,那么对象就会被释放。

    顺便说一句,请注意,scheduledTimerWithTimeInterval它建立了对其目标的强烈引用。您必须使用invalidate计时器来解析该强引用。

  2. ARC仅适用于引用类型(即class实例)。它根本不适用于值类型(例如数字类型或struct类型)。

    因此,考虑

    var number = 2 
    var othernumber = number
    
    Run Code Online (Sandbox Code Playgroud)

    othernumber引用number。它会制作一份副本。它是一个新对象,其值恰好与 相同number。有关区分 Swift 值类型和引用类型的讨论,请参阅 WWDC 2015使用值类型构建更好的应用程序。(顺便说一句,复杂值类型的幕后内存管理实际上比简单值类型更复杂,但它在本次对话中并不真正相关。但如果您是感兴趣的。)


Dun*_*n C 5

这是一个大问题。

为了理解 ARC,你确实需要理解手动引用计数。

引用计数是一种跟踪哪些对象仍在使用以及哪些可以被释放的方法。

在手动引用计数中,对象具有保留计数。

您向对象发送保留消息以增加其保留计数,并发送释放消息以减少其保留计数。如果向对象发送释放消息导致其保留计数降至 0,则该对象将被释放/释放。

还有一条autorelease消息将对象添加到“自动释放池”。每次代码返回并访问事件循环时,自动释放池中的所有对象每次位于自动释放池中时都会收到释放消息。(您可以向一个对象发送多个自动释放消息,但请忽略这一点。)自动释放对于返回临时对象非常有用,如果您不对它们执行任何特殊操作,这些对象就会消失。自动释放的对象会在当前调用链中保留下来,但如果没有人保留它,则当代码返回时会被释放。

对象被创建并返回给所有者,引用计数为 1,所有者负责在对象使用完毕后向该对象发送释放消息。

在手动引用计数中,您必须将保留、释放和自动释放调用放在代码中的正确位置,以表达您的内存管理意图。错误会导致内存泄漏或崩溃。

ARC 使用上述所有机制,但编译器会分析您的代码并为您插入保留、释放和自动释放调用。它还将多余的保留/释放调用删除到所需的最低限度。

在 ARC 中,您只需将变量声明为强或弱,编译器会完成其余的工作。虽然仍然存在一些问题,但大多数情况下您不必担心内存管理。

将对象存储在强变量中会导致编译器生成保留调用。将强变量清零会导致编译器向对象发送释放消息。

与垃圾收集不同,系统不必停止并对内存进行耗时的清理。一旦不再有任何强引用,对象就会被释放。