Memory Management in Swift

The weak, strong and unowned 😱

— Jordan Gellie

What is a Weak variable? You know, the one in front of IBOutlets. Looking through Apple’s documentation, I found Automatic Reference Counting (ARC). Apple uses ARC for memory management and to track memory usage.

Keywords like strong, weak, or unowned, signals to the ARC when to add or release a retain count.

The Strong, The Default 💪🏼

Each time we declare a class property, the default is a strong reference.

class Pokemon {
var name: String = "Pikachu"
var skill: Skill = Skill()
}

class Skill {
var type: String = "Pika Thunder"
}

let myPokemon = Pokemon()
print("My new Pikachu Skill: ", myPokemon.skill.type)

Pokemon has a skill property. When we create the Pokemon class, the Skill class is created as well. Therefore, the Pokemon class has a strong pointer to the Skill class and increases the retain count for Skill. When the Pokemon class gets deallocated, the pointer will be removed and the Skill class will decrease its retain count to zero.

Weak Reference

Wait, what if it’s a two way relationship where the pointers are pointing both ways? If the Skill class had a pointer pointing to the Pokemon class and the Pokemon class was assigned a value… we will create a retain cycle 🔄 which may lead to a memory leak 🙁

class Pokemon {
    var name: String = "Pikachu"
    var skill: Skill = Skill()
}
class Skill {
    var type: String = "Pika Thunder"
    var pokemon: Pokemon?
}
let myPokemon = Pokemon()
myPokemon.skill.pokemon = myPokemon
print("My new Pikachu Skill: ", myPokemon.skill.type)

Now we have two objects increasing each other’s retain count by one and there’s no way to decrease the count. This means the dealloc method will never get called on either objects.

We can easily fix this by… drum roll please 🥁🥁🥁

Using a weak reference!

The difference between a strong and weak reference is that a weak reference won’t increase the retain count of the object.

It’s usually considered best practice to have your parent marked as a weak.
class Pokemon {
    var name: String = "Pikachu"
    var skill: Skill = Skill()
}
class Skill {
    var type: String = "Pika Thunder"
    weak var pokemon: Pokemon?
}
let myPokemon = Pokemon()
myPokemon.skill.pokemon = myPokemon
print("My new Pikachu Skill: ", myPokemon.skill.type)
If you’re using a delegation pattern, you might want to mark your delegate as weak.

Unowned References

Unowned references assumes there is a reference, similar to implicitly unwrapped optionals.

Also..

Unowned references will not increase the retain count, just like weak references.

However, if you try and access an unowned reference and it’s not there, it will crash the app.

Conclusion

When creating reference types, strong and weak reference should be taken into consideration because memory management is important across all platforms.

Strong: 🐿 ➡️ 🌰

Weak: 🐿 ➡️ ⬅️ 🌰