2
votes

I just followed a tutorial on ARC and was provided with this code.

The following ViewController class and below it a Vehicle class.

What i got from it was that ARC essentially tracks down an instantiated class and allocates a piece of memory for it. As "strong" references for the instance are created, arc increases the increment for how many references there are to the instance. Once all of them are set to nil, ARC deallocates the instance from memory. The instructor also said something along the lines of, once all references are not being used, it deallocates from memory. I did not quite understand the part where they're not being "used", so I decided to add a button which presents another View Controller thats blank with no code. I figured that if I navigate to the next view controller, deinit will get called as the references in view controller 1, are now not being used and thus deallocated from memory. This was not the case, and the deinit did not get called. Therefore, I'm wondering, do references stay in memory unless you set them to nil, always?

Part 2 of question : Also, while you're answering that question, I also have another, I was also wondering if ARC only applied to class instances and references to it since every piece of documentation or tutorial that I have looked up seems to only mention class instances. For example, if I set var number = 2 var othernumber = number , is "number" also stored in memory, and only deallocated until all references to it are nil. If this is also the case, then the same question applies, is setting all references equal to nil the only way of deallocating from memory? Sorry for the lengthy question, but im quite new to the memory concept.

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

2 Answers

4
votes
  1. The "used" terminology is confusing/misleading (or, at best, imprecise). With ARC, the object will not be released until there are no remaining strong references, plain and simple. If you nil all of those strong references, or those strong references fall out of scope, that's when the object is deallocated.

    By the way, be aware that scheduledTimerWithTimeInterval establishes its own strong reference to its target. You have to invalidate the timer to resolve that strong reference.

  2. ARC only applies to reference types (i.e. class instances). It simply does not apply to value types (such as numeric types or struct types).

    Thus, consider

    var number = 2 
    var othernumber = number
    

    The othernumber does not reference the number. It makes a copy. It is a new object whose value happens to be the same value as number. For a discussion differentiating Swift value types from reference types, see WWDC 2015 Building Better Apps with Value Types. (By the way, the behind the scenes memory management of complex value types is actually more complicated than it is for simple value types, but it's not really relevant in this conversation. But it is discussed in some detail in the video if you're interested.)

3
votes

This is a big question.

In order to understand ARC you really need to understand manual reference counting.

Reference counting is a way of keeping track of which objects are still in use, and which can be deallocated.

In manual reference counting, objects have a retain count.

You send a retain message to an object to increase it's retain count, and release to decrease it's retain count. If sending a release message to an object causes it's retain count to drop to 0, the object is deallocated/freed.

There is also an autorelease message which adds the object to an "autorelease pool". Each time your code returns and the event loop is visited, all the objects in the autorelease pool get sent a release message for each time they are in the autorelease pool. (You can send more than one autorelease message to an object, but ignore that.) Autorelease is useful for returning temporary objects that go away if you don't do anything special with them. An autoreleased object sticks around during the current call chain, but get freed when your code returns if nobody has retained it.

Objects are created and returned to the owner with a reference count of 1, and the owner is responsible for sending a release message to the object when it is done with it.

In manual reference counting you have to put retain, release, and autorelease calls in your code at the correct places in order to express your memory management intentions. Getting it wrong causes either memory leaks or crashes.

ARC uses all of the above mechanisms, but the compiler analyzes your code and inserts retain, release, and autorelease calls for you. It also strips out excess retain/release calls to the bare minimum required.

In ARC, you just need to declare your variables as strong or weak and the compiler does the rest. There are still a few gotchas, but for the most part you don't have to worry about memory management.

Storing an object in a strong variable causes the compiler to generate a retain call. Zeroing out the strong variable causes the compiler to send the object a release message.

Unlike garbage collection, the system doesn't have to stop and do time-consuming cleanup passes on memory. Objects get freed as soon as there are no longer any strong references to them.