Why We Use [weak self] in Closures?

Damla Çim
4 min readFeb 23, 2023
Unsplash

Hey folks! In this article, we will talk about why we use [weak self] in closures. And this is about ARC and the references we use. We talked about ARC and references in the Interview series. If you want to take a look, you can check it out here.

Therefore, you must have researched this subject beforehand. I’ll continue assuming you know. If you are encountering the memory leak error a lot while writing the code, we will now clarify this issue.

Let’s answer this question first.

Why we use weak self?

The use of weak self in Swift is to prevent a strong reference cycle when using a closure that references an object, such as a view controller. A strong reference cycle can cause memory leaks and result in unexpected behavior of your application. It can also increase memory overhead and lead to crashes of your application.

In the context of iOS development, weak self is often used in closures to avoid strong reference cycles. For example, if you have a closure that captures self and self also has a strong reference to the closure, this can create a retain cycle. By capturing self weakly instead, you can break the retain cycle and ensure that both the closure and self can be deallocated when they are no longer needed.

In summary, using weak self in Swift is to prevent memory overhead and strong reference cycle.

I assume we understand why we use weak self and what is the benefit to us. We just talked about a new term. Let’s take a look at the strong reference cycle.

What is strong reference cycle?

A strong reference cycle, also known as a reference cycle or a retain cycle, is a situation in which two or more objects hold strong references to each other, creating a cycle that prevents the objects from ever being deallocated from memory. In other words, even though the objects are no longer needed, they cannot be automatically freed from memory because the strong references between them form a cycle that keeps them alive. This can lead to memory leaks, which can negatively impact performance and stability of the application over time.

Strong reference cycles are common in object-oriented programming and can occur in any programming language that uses reference counting or manual memory management. They are particularly prevalent in Objective-C and Swift, the programming languages used to develop iOS and macOS applications. To avoid strong reference cycles, it’s important to be mindful of the relationships between objects and to use weak or unowned references when appropriate.

Let’s see an example.

In this example, the closure captures the view controller self and weakly references it using [weak self]. Then, inside the closure, we use a guard statement to check if the self is still in memory, and if it is, we use strongSelf(a non-optional value, guaranteed to be non-nil) to access the properties and methods of the view controller. This way, we prevent a strong reference cycle and ensure that the view controller is deallocated when it’s no longer needed.

Okay, another example;

In this example, ExampleClass has a completion property that stores a closure that takes an Int argument and returns nothing. The performTask method starts a long-running task and, when the task is completed, calls the completion closure with the result of the task (in this case, 25).

The closure that is passed to the performTask method is stored in the completion property. Inside the closure that is run asynchronously, self is weakly referenced using [weak self]. If self is in memory the completion closure is called using self?.completion?(result).

I hope it’s descriptive. Let’s finish with a slightly more detailed example.

In this example, the ImageDownloader class has a method downloadImage that takes a URL and a completion closure, and downloads an image from the URL. The closure is called with the downloaded image (or nil if the download failed).

The closure is run asynchronously on a background queue, and self is weakly referenced using [weak self]. If self is in memory, the downloaded image is cached using self?.cacheImage(image, for: url). Finally, the completion closure is called with the downloaded image using completion(image). If [weak self] has deallocated self, self is nil. This does not cause a crash when executing the method.

I guess that’s all I want to say. I learned this while developing a chat app. The app was crashing all the time and my team lead was asking me why I didn’t use weak self in every code review. Thanks to my team lead, I’m using it now. I’m happy. See you soon!

--

--

Damla Çim

iOS developer at thecodebaseio | computer engineer