What you need to know about Memory Leaks in iOS (Part 1)

Tram Ho

If you know what ARC and memory leaks are in iOS, you can start Part 2. Here is a list of what we will learn:

  1. What is Memory Leaks in iOS
  2. Why Memory Leaks
  3. How ARC cannot release memory
  4. Memory Leaks in Closure
  5. Possible solutions
  6. Special circumstances (singleton and Static Classes Memory Leaks)
  7. Difference between weak and unowned
  8. Find the Leaks error by using the Memory Graph Debbuger
  9. A few essential rules

Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.

Section 1

Memory Leaks in iOS

Memory leak occurs when providing memory space that cannot be reused by ARC (Automatic Reference Counter) because it cannot know whether this device is actually used or not. One of the common problems with memory leaks in iOS is retained cycles, which we will cover later

Why doesn’t ARC free up memory?

Each time you create an object of a class, ARC will provide memory to store information about the object’s base. When the object is no longer used it will be freed so the question is how ARC defines an object as being in use. To understand this, we will look at how ARC works

Each variable is defined by a strong reference by default. When you create an object of a class with a strong reference, it increases the number of references on that object. Reference numbers are strong references to that object. When ARC looks at any variable with a reference number of 0, it frees the object’s memory:

swift var referenceOne: Person? = Person()

As the example above we create Person object. ARC will provide memory and store the reference to the referenceOne variable since that variable holds a strong reference to the Person ARC object will increase the reference count to 1 as shown below:

swift var reference2 = referenceOne

After doing the above, we create a strong reference to the Person object by assigning its address to the reference2 variable. Looking at Figure 2 below, the reference count is now 2 after assigning a strong reference to the Person object:

swift referenceOne = nil

By executing the above command we have removed a strong reference to the Person object by assigning the value nil to the referencOne variable to break the strong reference. Now, the reference count = 1 after removing a strong reference to the Person object as shown in Figure 3:

swift reference2 = nil

With the above action, we have removed a strong reference to the Person object by assigning the value nil to the argument reference2 . Now the reference count = 0.

When reference count = 0 ARC releases the Person object from memory. This is how ARC works

So how about memory leaks?

We already know how ARC works if it sees any bias with reference count = 0 it will release so that for areas where the reference counter never returns to 0 it will be possible to code with A class object never has a reference count when it has no strong reference. Let’s take a look at the example and find a solution for this case

Rule of thumb: If no object is owned, ARC will free memory OR

Without a strong reference to the entity of 1 ARC object will release OR

If reference count = 0 ARC frees memory OR

An object does not have a strong reference, it will be freed from memory

This is an example of a strong reference loop (meaning the reference count never returns to zero) generated by carelessness. As in Listing 5, we define two classes named User and Todo . The user has the todo attribute to refer strongly to the todo object as we said before because the default attribute is created by a strong pointer to the object:

By executing the above command we create the objects of User and Todo. ARC will provide memory and store strong reference of the User object to the user variable since this variable holds strong reference to ARC object entity will increase the reference count to 1 similar to todo object. As shown in Fig. 1, the user variable holds a strong reference to the User object while the todo object holds the Todo entity:

By executing the above commands we have done:

  1. First, we increased the reference count to the Todo object, now there are 2 strong pointers to it. Meaning it has 2 owners.
  2. Next, we increase the reference count to the User object, similarly above it now has 2 owners.

Ideally, when you change the Object to nil, the deinitializer function should be called. In some cases, even the deinitializer is not called when you set two variables to nil . Strong references between the User and Todo entities are still and unbreakable and there is no way to free up memory for objects. This is called a strong reference loop:

Solution

There are two solutions to this problem: making one of the attributes weak or unowned. The weak and unowned references allow the entity in the reference loop to reach another object without holding strong references to it. Entities can refer to other objects without creating a strong reference loop. Compared to strong, weak does not increase the reference counter.

As shown below, we create a weak attribute with the associatedUser name in the Todo class, which means assigning a User object to an attribute without increasing the reference counter / not holding a strong reference to the User object:

We create the User and Todo objects in the user and the todo variable does not hold a strong reference to the object, but it corresponds to make the reference between the two objects 1:

This is a way of linking together, User has a strong reference to Todo object which makes the reference count increase by 2 while Todo object has weak reference to User meaning it does not change the counter. reference:

user = nil

Setting the user to nil will reduce the User object reference number to 0:

Now ARC will check all objects whose reference counter originated from User object is zero, it frees up memory and strong, related references as shown below. The Todo object with the associatedUser property will be set to nil since it has a weak reference. The User object has now freed all strong references to it held because the property will become nil causing the Todo object reference set to be reduced to 1:

todo = nil

Setting todo to nil will cause the reference counter to be 0 and ARC will free the Todo object from memory. We will solve the strong reference loop problem by using the weak reference which makes us the first rule.

Rule 1:

When two objects have an interaction, they make one of them weak or unowned.

Memory leak in Closure

Memory leak in Closure = self references -> reference object -> self

Closures are closed blocks of functionality it can pass around as well as use in your code. Closure captures the variable and its constant from its surroundings.

Take a shot ?

As noted, Closure captures values ​​and constants from the scope around itself. Take a look at the following practice.

  1. First, we define two variables a and b with values ​​20 and 30, respectively. When we define any variable in a method it is only accessible inside it.
  2. Second, we define the someClosure variable it will capture a and b by making a strong reference to it to prevent those values ​​from being released and the closure to crash when they are released.
  3. When the someMethodThatTakeClosure method calls it will execute the closure and the closure will return the sum of a and b it takes from viewDidLoad . As shown below, the printed value is 50.

So that’s the end of part 1 of the translation , thank you for taking the time to read.

Share the news now

Source : Viblo