Should outlets be declared weak or strong? It’s a question that pops up surprisingly frequently. In this tutorial, I’d like to definitively answer this question. I also explain the why of the answer.
What Does Apple Recommend
Let’s first find out what Apple recommends. Fire up Xcode, create a new project based on the Single View Application template, and name the project Outlets.
Open Main.storyboard and add a label to the View Controller Scene from the Object Library on the right.
Open the Assistant Editor by pressing Option and clicking ViewController.swift in the Project Navigator on the left. Press Control and drag from the UILabel
instance to ViewController.swift in the Assistant Editor.
Name the outlet label
and click Create to have Xcode create the outlet.
As you can see, the outlet is declared strong. It’s a variable property of type UILabel!
, an implicitly unwrapped optional. The @IBOutlet
Interface Builder attribute indicates the property is an outlet.
@IBOutlet var label: UILabel!
Strong Versus Weak
What would change if you declared the outlet weak? Nothing. You can give it a try and run the application. Your application won’t crash and burn.
@IBOutlet weak var label: UILabel!
If there seemingly is no difference in behavior, then why is this important? Why are some developers declaring outlets strong while others define them weak? To be honest, many developers don’t know the difference. But that’s not you. Right?
Strong Outlets
To understand why outlets can be declared strong or weak, you need to be aware which objects keep a reference to which objects. That’s right. Reference counting.
Basics
Let’s start with the basics. Every view controller keeps a reference to the view it manages. That reference is strong. Why? The view should not be deallocated as long as the view controller is alive. That makes sense. Right?
You can verify this by opening ViewController.swift, pressing Command, and clicking UIViewController
. This takes you to the public interface of the UIViewController
class. As you can see, the view
property is declared strong.
@available(iOS 2.0, *)
open class UIViewController : UIResponder, NSCoding, UIAppearanceContainer, UITraitEnvironment, UIContentContainer, UIFocusEnvironment {
...
open var view: UIView!
...
}
What happens if a view is added to the view of the view controller? What happens, for example, if the label we added earlier is added to the view controller’s view at runtime? A view always keeps a strong reference to the subviews it manages. That makes sense because the label is still alive and visible even if we don’t declare an outlet for the label in the ViewController
class. It’s the label’s superview that keeps the label alive.
A view always keeps a strong reference to the subviews it manages.
When the view controller is deallocated, the view it manages is deallocated as well. This also means that any subviews the view manages are also deallocated. This isn’t new if you’re familiar with reference counting.
Deallocation
If the outlet for the label is declared strong, doesn’t that mean the view controller keeps the label alive? That’s right. But that isn’t a problem. Is it?
The moment the view controller is deallocated, it releases the label. The label is deallocated if no other objects hold a strong reference to it.
Weak Outlets
What happens if the outlet is declared weak? With the above in mind, can you predict what’s different? The view controller’s view still keeps a strong reference to the label. But the view controller keeps a weak reference to the label.
That isn’t a problem, though. The parent view or superview of the label keeps the label alive. When the view controller is deallocated, its view is also deallocated. As a result, any subviews the view manages are deallocated, including the label.
Are there any caveats? There are. What would happen if the view controller tries to access the label after the view of the view controller is deallocated? Because the outlet is declared weak, it is automatically set to nil
when it’s deallocated. Because the outlet is an implicitly unwrapped optional, it has no value, that is, is equal to nil
, and the application would crash as a result.
If this happens, chances are you’re doing something you shouldn’t be doing. You’ve gotten yourself into a race condition of some sort.
… But Be Careful
But there are exceptions. If you’re manipulating the view hierarchy of the view controller’s view, you need to take some precautions. For example, a view that is removed from the view hierarchy is no longer retained by the parent view it belonged to. If you want to keep a reference to that view, for example, you want to add it to the view hierarchy at a later moment, you need to make sure another object, such as the view controller, keeps strong reference to it.
Memory Management Rules Apply
I hope its clear that outlets are not magical or mysterious. The memory management rules that you’re already familiar with still apply. If you need a refresher, take a look at a series I recently wrote about memory management in Swift.
TL;DR
It doesn’t hurt to declare an outlet as strong. It’s what Apple recommends and it ensures the outlet has a value for as long the view controller is alive.