3 Thing to know about Memory Leak or Retain Cycle.
Variables, Closures and Protocols
Memory Leak is a nightmare for developers until you understand how memory management in iOS works. If you are looking for detailing of ARC this is not the right place. Here out primary consideration would be the cases where ARC couldn’t deallocate memory.
What is Retain cycle?
One line explanation would be, If an object initialised in your code couldn’t be deallocated on its own for some reasons then the retention cycle begins
Consider Bob and Alice holding each others hand, if Bob whats to leave the place Alice also should loosen his hand. If not, bob stays in memory even after he is not need in that place anymore. This circumstance is called retain cycle.
Possible occurrence of retain cycle
- Strong reference in class or struct
- Closures without weak or unowned
- Protocols
We will be going through each of the items with sample code blocks
Strong Reference in Class/Struct
We gonna bring Elon Musk and his Tesla model S for our demo 😄,
On executing the above playground, console logs would be ,
Elon Musk owns TESLA Model S
No deinit print was logged, the reason is both Vehicle and Person object refers strongly to each other. Same as Bob and Alice holding to each others hand. We have to loosen the knot by adding weak to object referred in Vehicle and Person class.
Diff in above code is,
weak var vechicle:Vechicle?
Updated console log is
Elon Musk owns TESLA Model SVehicle: TESLA Model S is being deinitilizedPerson: Elon Musk is being deinitilized
Holahhhh…. we have properly deallocated. Bob and Alice are set free now…
Closure without weak or unowned
Now we will be recreating the same memory leak scenario by using improper closure implementation.
This object has a strong reference to the closure and, since we used self in the closure block, the closure has a strong reference to the object itself.
We can solve this by adding weak self to the closure,
Now the closure doesn’t have a strong reference anymore. Diff from above code blocks are,
vehicle?.batteryFull = { [weak self] in
self?.unPlugCharger()
}
Another alternate way is to use unowned in the place of weak if we can guaranty the self will never be nil.
Just be careful when using [unowned self] since that, if the object has already been deallocated when the closure is called, a crash will occur.
Protocols
Using Protocols or Delegates will also lead into unallocated memory, now we gonna simulate retention cycle and will be providing fix as well.
As mentioned earlier above code will create memory leak, to avoid we have to set delegate var as weak.
Diff for fix is as follows,
protocol VehicleDelegate: class {
func batteryFull()
}weak var delegate:VehicleDelegate?
After above change our console log would be as follows,
Elon Musk owns TESLA Model SPerson: Elon Musk is being deinitilizedVehicle: TESLA Model S is being deinitilized
Great! Now you have learned to avoid retain cycles while using closures, protocols and var.
Found this post useful? Kindly tap the 👏 button below! :)
Leave you comments, queries and suggestions below.