IBOutlets are super common across iOS applications. When I first started to develop apps, I was always confused whether they should be weak or strong.
Should IBOutlets be weak or strong? The official answer from Apple is that IBOutlets should be strong. The only case when an IBOutlet should be weak is to avoid a retain cycle. A strong reference cycle can result in memory leaks and app crashes.
Apple states that we should usually keep the outlets strong but in what cases should we make them weak? Let’s dive into the details.
Strong and weak references in iOS refer to how the memory is managed.
A strong reference means that object will always stay alive and will be held in memory. It means this property ‘owns’ this address in memory. The compiler will ensure that an object that has a strong reference to it will never be destroyed.
A weak reference is the opposite. With a weak reference, you tell the compiler that you don’t want to have control over this objects lifetime. That is, if this object has no more strong references to it, it can be deleted. This happens immediately when the object has no more strong references to it. So you may find that this object becomes nil when you did not expect it to. There are certain use cases that a weak reference is used quite often:
Delegates are often stored as weak references as their actions are only useful if the object that built them is still alive. They should be automatically deallocated and cleared if the object receiving the call back is no longer alive. Otherwise, this could result in the delegate performing an action on a nil object which may result in an app crash.
Subviews often contain a reference to their parent view controller to send messages back. This can be done in the form of a delegate as well. This is used to update the view order or to tell the parent view controller when it should delete this subview. We don’t want a strong reference here as it would result in a strong reference cycle, also known as a retain cycle. This is because the parent view controller already has a strong reference to its subview.
Retain cycles are bad as they leak memory and can slow down your application. When a retain cycle is identified through the memory debugging tool or other diagnostics performed by an engineer, setting one of the references to weak is usually the solution. It can be sometimes be difficult to determine which property should be weak.
A retain cycle is when two or more objects hold strong references to each other in a cyclical fashion. Since they both hold references to each other, they will never be deallocated. Remember, objects will never be deallocated if there is one strong reference pointing to them.
In the case of a retain cycle, neither object will be deallocated from memory despite both of them being deleted. They will hold onto each other forever. This may sound like a minor problem or not a problem at all. However, if you have a lot of retain cycles in your application, this can leak a lot of memory. Eventually, this will result in an out of memory error which will crash your application.
IBOutlets for the most case should be strong as you’d like the elements of your view controller to exists as long as your view controller is alive. It would be unfortunate if you lost an image, button or label of your view controller while the view controller was still in memory!
By setting outlets to be strong in view controllers, you can ensure that all your UI elements will be in memory when you call upon them. If they were weak, you could experience a nil pointer exception when trying to change label text or capture user interaction with a button.
Once your view controller is removed from the screen and memory, you can ensure that all its children elements will be removed as well. This gives you control over when a view controllers elements are removed.
Subviews should be strongly referenced in the parent view. This ensures they’re not deallocated from memory as long as the parent view is alive.
The subview, if needed, should only have weak references to the parent view. This prevents a retain cycle or a strong reference cycle from occurring. Otherwise, if both the parent view and the subview have strong references, this will likely result in memory leaks.
Subviews may need a reference to the parent view if there are functions that rearrange or resize the parent view based on subview behavior. For example, if a subview wants to change its order on the parent view, it will need a method to communicate to the parent view.
Delegates should almost always be weak references. This is because if the delegator is deallocated from memory, the delegate is no longer needed. If the delegator is nil and the delegate tries to perform an action on it, this will result in a nil exception and crash the application.
Strong delegate references are one of the leading causes of memory leaks and iOS developers should be very careful before creating a strong delegate reference.
What is an IBOutlet? Interface builder outlets (IBOutlets) are properties of an object that reference an object archived by the interface builder. The connections between the object and its outlet are established when the nib file is loaded during the build process.
What is a delegate? Delegates are a part of a design pattern in Swift. Delegates are objects that perform actions based on a defined protocol. A delegator object initializes these delegates and has them perform actions based on conditions.
What is a memory leak? Memory leaks are when certain addresses in memory are never cleared by the app. This results in “lost” memory during the apps life cycle. The most common problem that causes this is strong reference cycles also known as retain cycles.