slimboy slimboy - 3 months ago 12
Swift Question

ARC and how it works exactly.

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

}}

Rob Rob
Answer
  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.)

Comments