Press ESC to close

Strong – Unowned – Weak Types

Hello friends, in this article we will talk about the most used structures for Swift Memory Management. Earlier, I talked about how ARC works. You can find that article here. While creating variables in Swift programming language, you can create 3 different types of variables. These; Strong, Weak and Unowned.

Strong

When you create a variable, its type is Strong by default. A variable of type Strong increases the reference count by 1 in Swift’s ARC structure. This variable is not deleted from RAM unless this increment is 0. Therefore, a Memory Leak may occur.

Weak

When you create a weak type variable, it does not increase the reference number from the ARC structure by 1. For this reason, a Retain Cycle situation will not be in question, so it is easily deleted from the memory. The variable must be optional when creating a weak reference.

Unowned

It has a weak-like structure. The difference is that it is nonoptional. For this reason, a value must be given when creating the variable.

In the example we will do below, we will create a Memory Leak and then provide its solution. In our example, let’s have a customer class and a credit card class. Every customer can have a credit card, and every credit card must have a customer. After defining the classes, I can follow the output by running the print functions on the init and deinit functions.

Let’s not forget that memory leak can only occur in reference type variables. For this reason, there is no memory leak in value type variables such as struct or enum.

After creating our classes, I create a customer and credit card and set them to the classes I created. After I’m done, I set these variables to nil and wait for them to be deleted from RAM, but we see that the functions we put in the Deinit function do not work. The reason is that the reference number cannot be 0. In the example below, I wrote the reference numbers as comments.

import UIKit

class Customer {
    let name: String
    var creditCard: CreditCard?
    
    init(name: String) {
        self.name = name
        print("Customer \(name) initialized")
    }
    
    deinit {
        print("Customer \(name) deinitialized")
    }
}

class CreditCard {
    let creditCardName: String
    var customer: Customer?
    
    init(creditCardName: String) {
        self.creditCardName = creditCardName
        print("CreditCard \(creditCardName) initialized")
    }
    
    deinit {
        print("CreditCard \(creditCardName) deinitialized")
    }
}

var customerOmer: Customer?
var creditCardTest: CreditCard?

customerOmer = Customer(name: "Omer Sezer") // customerOmer's reference count = 1
creditCardTest = CreditCard(creditCardName: "Test Credit Card") // creditCardTest's reference count = 1

customerOmer?.creditCard = creditCardTest // creditCardTest's reference count = 2
creditCardTest?.customer = customerOmer // customerOmer's reference count = 2

customerOmer = nil // customerOmer's reference count = 1
creditCardTest = nil // creditCardTest's reference count = 1

Although I set the variables I created to nil, they are not deleted from RAM and remain in RAM even though I will never use them again. This way, imagine that many of our variables are not used internally and are sitting idle in RAM. After a while, the application will start to contract and the phone will start to warm up. For this reason, we must consider these when creating a variable.

As a solution, we have to establish the logic of the structure here. Every credit card must have a customer, but not every customer has to have a credit card. So we can define the credit card variable in the Customer class as weak . Since the reference of the variable we define as weak will not increase by 1, it will be deleted from the RAM and prevent a Memory Leak from occurring.

import UIKit

class Customer {
    let name: String
    weak var creditCard: CreditCard?
    
    init(name: String) {
        self.name = name
        print("Customer \(name) initialized")
    }
    
    deinit {
        print("Customer \(name) deinitialized")
    }
}

class CreditCard {
    let creditCardName: String
    var customer: Customer?
    
    init(creditCardName: String) {
        self.creditCardName = creditCardName
        print("CreditCard \(creditCardName) initialized")
    }
    
    deinit {
        print("CreditCard \(creditCardName) deinitialized")
    }
}

var customerOmer: Customer?
var creditCardTest: CreditCard?

customerOmer = Customer(name: "Omer Sezer") // customerOmer's reference count = 1
creditCardTest = CreditCard(creditCardName: "Test Credit Card") // creditCardTest's reference count = 1

customerOmer?.creditCard = creditCardTest // creditCardTest's reference count = 1
creditCardTest?.customer = customerOmer // customerOmer's reference count = 2

creditCardTest = nil // creditCardTest's reference count = 0
customerOmer = nil // customerOmer's reference count = 0

More information can be found here. If you have questions, you can reach them by sending an e-mail or comment.

Comments (6)

Leave a Reply

Your email address will not be published. Required fields are marked *