Strong VS Weak/Unowned References & ARC in Swift

Ahmed Menaim
5 min readDec 30, 2020

The first thing comes to your mind after seeing the title and picture that you are comparing between two persons from their strength but in programming languages especially swift you will have another point of view, you are still comparing but not persons but references and the difference here that you have a superhero by your side which called ARC “Automatic Reference Counting”

ARC is helping to track and manage memory to free it from unused references to be able to avoid retain cycle (Memory leak) which happens when references don’t be de-allocated by ARC. However, a strong reference cycle can happen when two objects hold a strong reference to each other.

Let’s say that you have your company called Memory and you are holding the position of the manager for this company and your name is ARC, so you if you have a freelancer called Class instance will come to your company for a specific time, you have to free an office for him to be able to implement his job and then he will left it after finishing, Of course you must be sure that this class instance is strong at his position and had strong background to be able to finish his work and as a manager you will be 100% sure that you can let the Class instance freelancer left the company till being sure that he completely finished his work and this is called Strong reference.

It is okay to use a strong reference when the flow is from parent to child like below:

class Company {
var name: String
init(name: String) {
self.name = name
print("Company name is \(self.name)")
}
deinit {
print("Company name \(self.name) is deinited successfully")
}
}
class Worker {
var name: String
var company: Company
init(name: String, company: Company) {
self.company = company
self.name = name
print("worker name is \(self.name)")
}
deinit {
print("worker name \(self.name) is deinited successfully")
}
}

var company: Company? = Company(name: "FTG")
var worker: Worker? = Worker(name: "Menaim", company: company!)

company = nil
worker = nil

Output:
Company name is FTG
worker name is Menaim
worker name Menaim is deinited successfully
Company name FTG is deinited successfully

So here you made your company as a manager and after finishing everything, you don’t need your worker anymore and that’s why you freed the job by setting it = nil, All of these explained why did you as a manager “ACR” de-initialized the instances successfully, but sometimes you may meet an obstacle as a manager, when you add more than freelancer and you can see that job is ended and you still adding some freelancers to your company which will cause “Memory leak” and preventing you from implementing de-initializing:

class Company {
var name: String
var workers = [Worker]()
init(name: String) {
self.name = name
print("Company name is \(self.name)")
}
deinit {
print("Company name \(self.name) is deinited successfully")
}
}
class Worker {
var name: String
var company: Company
init(name: String, company: Company) {
self.company = company
self.name = name
company.workers.append(self)
print("worker name is \(self.name)")
}
deinit {
print("worker name \(self.name) is deinited successfully")
}
}

var company: Company? = Company(name: "FTG")
var worker: Worker? = Worker(name: "Menaim", company: company!)

company = nil
worker = nil

Output:
Company name is FTG
worker name is Menaim

So now you will pay more for your freelancer workers but you won’t take a work from them as you make a short term contract with them “Strong reference cycle” but there is no work for them to do which causes “Memory Leak”

But all of the previous was just a plan you created to be able to see the future and to avoid these obstacles and after seeing all of this you decided to find another solution to be able to fit your budget and bring suitable Freelancers to your company which is using a contract with a special case called (If we don’t have more work you will be out of the company) “Weak references” instead of our short term contract which was called “Strong references”:

class Company {
var name: String
var workers = [Worker]()
init(name: String) {
self.name = name
print("Company name is \(self.name)")
}
deinit {
print("Company name \(self.name) is deinited successfully")
}
}
class Worker {
var name: String
weak var company: Company?
init(name: String, company: Company) {
self.company = company
self.name = name
company.workers.append(self)
print("worker name is \(self.name)")
}
deinit {
print("worker name \(self.name) is deinited successfully")
}
}

var company: Company? = Company(name: "FTG")
var worker: Worker? = Worker(name: "Menaim", company: company!)

company = nil
worker = nil

Output:
Company name is FTG
worker name is Menaim
worker name Menaim is deinited successfully
Company name FTG is deinited successfully

As a manager you have to save the company safety and that’s why you decided to add Weak to your worker to be able to let him go if you don’t have work to him anymore, Weak means: That you have a pointer to an object which can’t protect the object from being de-allocated by ARC but as a manager you have to be sharp at everything and that’s why you may notice that Weak reference is always optional which make the contract vulnerable as you are giving the the freelancer the option to leave once he needs even if he didn’t finish his work he has the right to go so you decided to add a different thing called Unowned reference which gives you the right to make it optional or not which helps you to manage workers easily and to control the contract as you can but it’s the same as Weak in everything else:

class Company {
var name: String
var workers = [Worker]()
init(name: String) {
self.name = name
print("Company name is \(self.name)")
}
deinit {
print("Company name \(self.name) is deinited successfully")
}
}
class Worker {
var name: String
unowned var company: Company?
init(name: String, company: Company) {
self.company = company
self.name = name
company.workers.append(self)
print("worker name is \(self.name)")
}
deinit {
print("worker name \(self.name) is deinited successfully")
}
}

var company: Company? = Company(name: "FTG")
var worker: Worker? = Worker(name: "Menaim", company: company!)

company = nil
worker = nil

Output:
Company name is FTG
worker name is Menaim
worker name Menaim is deinited successfully
Company name FTG is deinited successfully

According to Apple’s docs:

Use an unowned reference only when you are sure that the reference always refers to an instance that has not been de-allocated.

If you try to access the value of an unowned reference after that instance has been de-allocated, you’ll get a runtime error.

Thanks for reading️! Help spread the word & wait for the coming articles…

Have questions, suggestions, comments, or ideas for upcoming blog posts? Contact me on LinkedIn or write a comment! You can also follow me on GitHub & check my Stackoverflow answers and questions.

--

--

Ahmed Menaim

iOS / Software Engineer / Building iOS Apps / Spread knowledge