Swift Memory Management — When it’s important

Memory management in swift is mainly handled by ARC (which I talked about here). ARC is an incredible, and reliable, technology that allows us programmers to worry about the bigger scope of our projects without having to worry about memory management. However, there are cases where using specific references are important, for the simple reason that sometimes ARC has no clue what to do with objects in certain situations. Especially when dealing with closures (which has been a recent topic in the Flatiron School iOS curriculum this past week) you may run into what’s called a “retain cycle”. Alright, with that out of the way, let’s talk about the three reference types in Swift.

Strong

A Strong reference type is the default in swift. The Strong reference essentially tells the compiler that as long as an object has a Strong pointer to it, it will always exist (aka never get deallocated). For the most part, using Strong as a reference type is relatively safe, there’s only a few places where you’ll run into issues. One such issue is when two objects both have Strong references to each other. Essentially, this creates what is called a “reference loop”. This means that both objects will stay on the heap forever, never to be deallocated.

Weak

Weak pointers can best be described as optionals — they either are a value or they are nil. Therefore, you always have to use a var when declaring a weak reference pointer, so the value can be changed. When an object has a Weak reference type it means that the object can be deallocated soon as no other objects utilize it. When this is especially important is when referring to Self within closures. Why? Well when you reference something from outside the scope of the closure within the closure itself, the closure retains that object since the closure and the object both have a Strong reference to each other. To fix this, you have to manually set Self to a Weak type (demonstrated below). When one object is strong, the other should be set to weak/unowned in order to break the cycle.

...(argument: () -> ()){ [weak self] in 
self.exampleClass.methodInClass
}

So why is this important? Well since we’ve been using closures, it’s important to understand the limitations of ARC in regards to handling closures. This is especially apparent when you reference self within a closure. Why? Well closures are referred to as “first-class citizens” in swift, so they essentially act like a class when you call them. That means, they hold on to any value for as long as the closure is in operation. When you reference self, it is inherently strong, so the closure within the class are both referencing each other strongly, which thus creates a reference loop. How do you break this? You have to manually specify self as a weak type when writing your closure as to not increase your reference count by one.

Unowned

Unowned is more or less the manual way of dealing with memory. Similar to implicitly unwrapped optionals, you’re guaranteeing the compiler that you know where what points to where. This is helpful if you know for a fact what something is doing and why.

Capture lists

You can also do another cool thing in swift within closures called capture lists, which essentially is just an array of objects with a specific memory reference type. So if you want to manually set two or more objects to a specific memory type in swift, you would use a capture list to do this.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.