Swift: weak and unowned
With the keywords weak and unowned you can avoid so-called reference cycles. In this post we will discuss the differences between them.
References Cycles
As I’ve described already in my blog post “A Trick To Discover Retain Cycles”, it is still important to do some kind of memory handling, although ARC does most of the work for you:
First we are creating a RootViewController and a SecondViewController. The SecondViewController gets presented, if a button on the RootViewController is pressed. You can create this easily by using a segue in the storyboard of the app. Furthermore, there is a class called ModelObject, which has a delegate object of type ModelObjectDelegate. If the SecondViewController‘s view is loaded, the controller sets itself as the delegate of the ModelObject:
import Foundation protocol ModelObjectDelegate: class { } class ModelObject { var delegate: ModelObjectDelegate? }
import UIKit class SecondViewController: UIViewController, ModelObjectDelegate { var modelObject: ModelObject? override func viewDidLoad() { super.viewDidLoad() modelObject = ModelObject() modelObject!.delegate = self } @IBAction func closeButtonPressed(sender: UIButton) { dismissViewControllerAnimated(true, completion: nil) } }
Ok, now let’s examine the memory handling: If we are dismissing the SecondViewController, the amount of used memory is not decreasing. But why is this? We would expect that with the dismiss of the SecondViewController memory gets deallocated. Let’s take a look at the objects. If the SecondViewController is loaded, it looks like this:
Now, if the SecondViewController is dismissed, it looks like this:
The RootViewController doesn’t have a strong reference to the SecondViewController anymore. However, the SecondViewController and the ModelObject have strong references to each other. And because of this they are not deallocated.
Weak
To avoid this behaviour, you can declare a reference as weak, which does not prevent ARC from deallocating the memory:
import Foundation protocol ModelObjectDelegate: class { } class ModelObject { weak var delegate: ModelObjectDelegate? }
The object graph looks now like this:
Because there is just one strong reference between the SecondViewController and the ModelObject, there is no problem anymore in deallocating the memory.
Unowned
But instead of weak you can also use unowned. But what is the difference? If you are using weak, the property hast to be an optional, so it is allowed to become nil. If you are using unowned on the other hand, it must not be an optional. Since an unowned property is not an optional, its value has to be set in the init method:
import Foundation protocol ModelObjectDelegate: class { } class ModelObject { unowned var delegate: ModelObjectDelegate init(delegate:ModelObjectDelegate) { self.delegate = delegate } }
Depending on the property – optional or not – you have to choose between weak or unowned.
References
A Trick To Discover Retain Cycles
Optionals In Swift
Swift Programming Series (iBook Store)
Image: @ Fabrik Bilder / shutterstock.com