SoFunction
Updated on 2025-04-09

In-depth explanation of Swift's memory management

Preface

The goodness of LLVM compiler: In addition to paying attention to reference loops, Swift's memory management is almost entirely covered by LLVM compilers, and developers do not need to worry about it.

Swift automatically manages memory, which means we no longer need to worry about memory application and allocation. When we create an object through initialization, Swift manages and allocates memory for us. The principle of release follows the rule of automatic reference counting (ARC): when an object has no reference, its memory will be automatically recycled. This mechanism greatly simplifies our encoding. We only need to ensure that the reference is empty at the appropriate time (such as exceeding the scope, or manually setting it to nil, etc.) to ensure that memory usage does not occur.

However, all automatic reference counting mechanisms have a theoretically unavailable limit, which is the case of circular references.

What is the problem of citation loop

Swift uses the ARC (automatic reference counting) method to manage memory for reference types.

In Swift, when declaring a variable of reference type and giving the object negative value to it, it is equivalent to creating a strong reference to the object, and the reference count of the object will be increased by 1. If two objects refer to each other strongly, a reference loop will be caused. Once a reference loop occurs, the related objects will not be released, resulting in a memory leak.

Scenarios and solutions to the citation loop problem

In Swift, class objects and closures are passed through references, so the following scenario will have a reference loop:

Class objects are mutually referenced

When two objects refer to each other, a reference loop forms.

class Letter { 
 let addressedTo: String 
 var mailbox : MailBox? 

 init( addressedTo: String) {
 self. addressedTo = addressedTo 
 } 

 deinit { 
 printl(" The letter addressed to \(addressedTo) is being discarded") 
 } 
}

class MailBox { 
 let poNumber: Int 
 var letter : Letter? 

 init( poNumber: Int) {
 self. poNumber = poNumber 
 } 

 deinit { 
 print("  Box \(poNumber is going away)") 
 } 
}

The MailBox class object is strongly referenced in the Letter class object, and the MailBox class also strongly referenced in the Letter class object to form a reference loop.

Solution: Adding the weak keyword (weak reference) when declaring an object can unreference it. For example, when declaring a letter object as weak, the reference count of the mailbox object will not be increased by 1, thus dereference looping. An object that logically belongs to another object is generally declared as a weak object. like:

weak var letter : Letter?

References to objects containing themselves in the closure

Referring to objects containing themselves in a closure can also cause a reference loop.

class MailChecker { 
 let mailbox: MailBox 
 let letter: Letter 

 lazy var whoseMail: () -> String = { 
 return "Letter is addressed to \(self. )"
 }

 init(name: String) { 
 self. mailbox = MailBox( poNumber: 311) 
 self. letter = Letter( addressedTo: name) 
 } 

 deinit { 
 println(" class is being deintialized")
 }
}

In the example code, the whoseMail closure uses self to refer to the MailChecker object containing itself. At this time, the closure has the MailChecker object, and the MailChecker object has the closure, resulting in a reference loop.

Solution:At this point, you can add [unowned self] to let Swift know that the self object should not be retained, thereby dereferenced looping. Change the closure to:

lazy var whoseMail: () -> String = { [unowned self] in
 return "Letter is addressed to \(self. )"
}

Note: All codes are taken from Boisy G. Pitre "Swift Basic Tutorial"

Summarize

The above is the entire content of this article. I hope the content of this article will be of some help to all iOS developers. If you have any questions, you can leave a message to communicate. Thank you for your support.