# Different ways to detect memory leaks
###### tags: `memoryleak`
* [Overview](#Overview)
* [Alternatives](#Alternatives)
* [Lifetime tracker](#Lifetime-tracker)
* [XCode Instrument](#XCode-Instrument)
* [Leaked view controller detector](#Leaked-view-controller-detector)
* [Unit tests](#Unit-tests)
* [Summary](#Summary)
## Overview
Memory leaks and retain cycles are two common issues that can arise in iOS app development, leading to degraded app performance and eventual crashes.
Both memory leaks and retain cycles can be difficult to detect and diagnose, as they often occur gradually over time and may not cause immediate issues. To avoid these issues, developers should be vigilant in managing memory usage, using tools to detect memory leaks and addressing any retain cycles in their code. Proper use of ARC (Automatic Reference Counting) can also help manage memory usage and prevent retain cycles.
## Alternatives
In this document, I will walk you through some of the possible solutions that can help us to avoid aforementioned problems, and build the best user experience to our customers.
---
### [Lifetime tracker](https://github.com/krzysztofzablocki/LifetimeTracker)
#### Overview
It is a 3rd party library that can surface retain cycle / memory issues right as we develop new features. It shows memory leaks/retain cycles inside bottom sheet if detected any:

#### Integration
To integrate this library to our project, we need to:
1. Add `LifetimeTracker` to our `Podfile` (or use `SPM`).
2. Conform to `LifetimeTrackable` protocol for clasees we want to track.
3. Call `trackLifetime()` method on those object's initialization.
4. Setup global configurations like logging, styling etc.
#### Disadvantages:
* It is a 3rd party library and according to our OKRs, we should avoid adding another 3rd party dependency unless there is no way around.
* Every object that we plan to track should conform to `LifetimeTrackable` protocol and call `trackLifetime` method. *(We can create base classes like `BaseViewModel`, `BaseView`, `BaseDataService`. However, it can create some problems when if we want to create seaparate modules)*
* Issue cannot be noticed unless that specific view is visited, or an action that triggers memory leak is triggered.
---
### XCode Instrument
#### Overview
It works by analyzing the memory usage of an app at runtime and identifying any instances where memory is allocated but not properly released.
The memory leak instrument provides a detailed report of memory usage over time, showing developers where memory is being allocated and where it is not being released. It also provides information on the size of the memory leaks and the location in the code where they are occurring, making it easier for developers to track down and fix the issues.

#### Disadvantages:
* The memory leak instrument can sometimes miss memory leaks that are present in an app. This can happen if the leak occurs in a part of the code that is not being monitored by the instrument, or if the leak is occurring in a way that is difficult to detect.
* The instrument takes quite a long time to run, and since not a good option to be used daily
---
### [Leaked view controller detector](https://github.com/Janneman84/LeakedViewControllerDetector)
#### Overview
`LeakedViewControllerDetector` helps to find leaked views and controllers. Upon detecting any issue, it instantly shows a warning alert dialog (in debug builds). Also, it can log warning messages to `DataDog`. Installation is easy, simply copying one `.swift` file into the project is enough. ***[Reference for reading](https://swiftpackageindex.com/Janneman84/LeakedViewControllerDetector)***
#### Disadvantages:
* Currently, it can only be used with `UIKit` components. Thus, we cannot add this safety to `SwiftUI` or `ViewModel` objects.
* Issue cannot be noticed unless that specific view is visited, or an action that triggers memory leak is triggered.
* A lot of customization should be made for edge cases where the view / view controller should be kept in the memory.
* Not consistent.
---
### Unit tests
Detecting memory leaks using unit tests in Swift can be a useful technique for identifying and addressing memory issues in an iOS app. Here's how we can do it:
#### Implementation
This extension below, adds a teardown block to any object to detect potential memory leaks:
```Swift=
import XCTest
extension XCTestCase {
func trackForMemoryLeaks(_ instance: AnyObject, file: StaticString = #file, line: UInt = #line) {
addTeardownBlock { [weak instance] in
XCTAssertNil(
instance, "Instance should have been deallocated. Potential memory leak.",
file: file,
line: line
)
}
}
}
```
Consider the following example from `What's New Stories` module. The `sut` (system under test) is being created using a helper method. The helper method adds the `sut` instance for tracking:
```Swift=
final class WhatsNewStoriesManagerTests: XCTestCase {
func test_initTriggersLoad() {
let (_, dataService) = makeSUT()
XCTAssertEqual(dataService.loadCallCount, 1)
}
// MARK: - Helpers
private func makeSUT(file: StaticString = #file, line: UInt = #line) -> (sut: WhatsNewStoriesManager, dataService: MockWhatsNewDataService) {
let dataService = MockWhatsNewDataService()
let sut = WhatsNewStoriesManager(dataService: dataService)
trackForMemoryLeaks(sut, file: file, line: line)
return (sut, dataService)
}
}
```
Thus, when there is a memory leak, it is represented as following:

#### Advantages:
* No third party library.
* Can be applied to any type of class
* No setup is required in production code
* Fast and reliable, since that specific screen is not required to be opened, or activated.
#### Disadvantages:
* The approach explained above is not possible with `Quick/Nimble` setup, thus, requiring us to have two different testing approaches in our code base.
* Currently, we do not have test coverage for view controllers and views.
---
## Summary
Considering all the points mentioned above, we can choose the last option as a potential solution to our existing problems with memory management, since no depending on the 3rd party code is required, and the approach can be used with any kinds of object (not limited to UIKit components).