Does [weak self] always need to be used in closures ???

Tram Ho

For an iOS developer, no one has not heard of memory leak, retain cycle, etc. are all problems related to memory loss. And it is impossible not to mention [weak self] as a method to prevent this from happening.

1. Automatic Reference Counting.

The memory in Swift is managed by ARC mechanism, it operates by calculating the number of references to the device.

It will be freed when no object references it. So in some cases you cannot release it because there is still a strong reference to it so you should learn how to use [weak self]

Some methods to check memory leak:

  • Check in deinit () function when ViewController is closed.
  • Observe the increasing memory level
  • Use the Allocations Instruments tool

2. Unowned, weak and Strong – weak

Closues can strongly capture any variable or constant in the context in which it is defined. For example, if you use self in closures, it will be maintained throughout the scope of that scope. And if self keeps a strong reference it will lead to a strong reference cycle.

That’s why you need to use [weak self] or [unowned self] to avoid that. However, be careful when using unowned, if that object nil, the app will crash.

For example:

3. Escaping and non-escaping closures

In Swift, there are two types of closures: escaping and non-escaping.

  • Non-escaping closures execute code within its scope immediately and are not able to be stored or used later.
  • Escaping closures can store it in another variable or closure and may execute it in the future.

Therefore non-escaping such as the higher order function and does not cause a reference cycle, so it will not require using weak or unowned. As with escaping, it can cause reference cyclé when not using weak or unowned. However only if it guarantees the following 2:

  • Closures are stored in one variable or another closures.
  • Can use self to reference in closure.

The chart below will help you see when to use [weak self]

4. Delay deallocation

In the chart above you can see the mention of delay deallocation. This is a side effect that both escaping and non-escaping can occur.

It is not a direct cause of a memory leak, but it will cause a few unwanted things. For example, when the VC is dismissed but the closure is still blocked, the VC will not be deinit at that time.

Let’s analyze with the example below

In the above code, there is a closure and does not use weak self or unowned self and the closure is not stored, implemented immediately. So this case will not cause memory leak.

However, the download task will take time, so while the task is executed that ViewController is canceled, it will not be released immediately, but need to wait for the task to complete. -> Causes an unwanted delay. So you can use weak self to prevent this from happening.

5. ‘guard let self = self’ vs Optional Chaining

When using [weak self] we created an optional variable so when using we need to unwrap or use optional chaining. Here we will talk about how to unwrap using guard let.

If the closure has a time-consuming task and can generate a delay dealloc, the use of guard let in the first place can not avoid that. Like the following example:

The use of guard let is that we compare self with nil, otherwise nil we will create a strong reference to use in scope -> the cause of delay deallocation.

As for using optional chaining, it will look like:

Using optional chaining, we will compare self with nil at each command line, if nil will be ignored and not create a strong reference here.

6. Some examples

6.1 Grand Central Dispatch

GCD usually does not cause reference cycles unless it is stored for later use. The following example does not cause a memory leak because it executes immediately:

However, if you store GCD in a variable as follows, it will cause a leak:

6.2 UIView.Animate and UIViewPropertyAnimator

Similar to GCD it also does not cause memory leak if it is not stored in the property.

Safe case:

Case causes menory leak:

6.3 Store closure in property

For example in ViewController1 1 closure and closure ViewController2 reference to which it should use to weak self

Then ViewController2 will be as follows:

7. Summary

Through this we can draw a few conclusions as follows:

  • [unowned self] is an unsafe solution
  • Non-escaping does not need [weak self] unless it causes a dealloction delay
  • Escaping closure requires [weak self] if it is stored or passed into another closure and has a self reference in it.
  • GCD, aimation usually doesn’t need [weak self] if it’s not stored in a variable for later use.
  • If you are unsure then consider deinit and Instruments.


Share the news now

Source : Viblo