ARC以及它如何正常工作。

时间:2016-08-25 23:50:39

标签: ios swift memory-management automatic-ref-counting

我刚刚关注了ARC的教程,并提供了此代码。

以下ViewController类及其下方的Vehicle类。

我得到的是ARC本质上追踪一个实例化的类并为它分配一块内存。由于创建了实例的“强”引用,因此arc增加了实例的引用数量的增量。一旦所有这些都设置为nil,ARC就会从内存中释放实例。教师还说了一句话,一旦所有引用都没有被使用,它就会从内存中解除分配。我不太明白它们没有被“使用”的部分,所以我决定添加一个按钮,它显示另一个没有代码的空白视图控制器。我想如果我导航到下一个视图控制器,deinit将作为视图控制器1中的引用被调用,现在不被使用,因此从内存中释放。情况并非如此,并且deinit没有得到调用。因此,我想知道,除非你把它们设置为零,否则引用会留在内存中吗?

问题的第2部分:另外,当你回答这个问题时,我还有另一个问题,我也想知道ARC是否只应用于类实例并引用它,因为我查找了每一个文档或教程似乎只提到类实例。例如,如果我设置var number = 2 var othernumber = number,则“number”也存储在内存中,并且只有在所有对它的引用都为nil之前才会释放。如果情况也是如此,那么同样的问题是适用的,是将所有引用设置为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


    }


}

}

   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")

}}

2 个答案:

答案 0 :(得分:3)

  1. “使用过的”术语令人困惑/误导(或者,充其量是不精确的)。使用ARC,在没有剩余的强引用之前,对象将不会被释放,简单明了。如果nil所有这些强引用或那些强引用都超出了范围,那就是取消分配对象的时候。

    顺便提一下,请注意scheduledTimerWithTimeInterval建立了自己对目标的强烈引用。您必须invalidate计时器来解析该强引用。

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

    因此,请考虑

    var number = 2 
    var othernumber = number
    

    othernumber未引用number。它制作副本。它是一个新对象,其值恰好与number的值相同。有关区分Swift值类型与引用类型的讨论,请参阅WWDC 2015 Building Better Apps with Value Types。 (顺便说一句,复杂值类型的幕后内存管理实际上比简单的值类型更复杂,但它在这个对话中并不真正相关。但如果你是在视频中详细讨论它感兴趣。)

答案 1 :(得分:1)

这是一个很大的问题。

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

引用计数是一种跟踪哪些对象仍在使用中以及哪些对象可以解除分配的方法。

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

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

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

创建对象并将其返回给所有者,引用计数为1,并且所有者负责在完成对象时向对象发送释放消息。

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

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

在ARC中,您只需要将变量声明为强或弱,编译器将完成剩下的工作。还有一些陷阱,但在大多数情况下,你不必担心内存管理。

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

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