Another unowned/weak article
I’m pretty sure you already know a lot about unowned/weak/strong memory quantifiers. But did you ever think about, how these quantifiers can create crashes on some devices in 70% cases and 30% on other? Why usage of unowned can become a problem in some cases?
Code to discuss
Let’s discuss following code snippet.
I know you use that a lot:
controller.choiceHandler{ [unowned self] (choice) in
self.currentChoice = choice
controller.dismiss(animated: true)
}
self.present(controller, animated: true)
So here, you create controller, that allows user to make some choice(let’s pretend user chooses city). So, when user chooses we update current choice and dismiss controller. What is the problem here?
Let me give you some statistics. Code fails on:
- Devices of iPhone 7 and earlier in 30%
- Devices of iPhone 8 and older in 70%
Interesting, ha?
Some theory.
First, why do we use weak/strong quantifiers?
The main reason is memory management. Creating strong references between object can become a loop, and lead to a memory leak.
iOS uses reference counting for handling effective release of objects that are not being used anymore to free up memory. And even though we have ARC(Automatic Reference Counting) in Xcode, it is not panacea. ARC works at compilation time, so it puts some code like retain/release for making it work. But in some cases you need to think about your object reference loop.
Look at this picture:
On this picture, we see two objects. Both of them have reference to each other. So what will happen when we release both of those object? Their reference count will always be at least 1, so the system will not “erase” them and they will always stay in memory. What if those objects are something heavy, like controller with many UI components and internal data? At some point you will face a crash, as iOS limits available memory for the application depending on OS version and device.
How to deal with that? Introduce weak reference for one of the objects which is going to be released first:
Here, when ObjectB will be released, ObjectA does not “own” the object and does not affect reference count of ObjectB, so that ObjectB will be released and will free up the occupied memory.
But what will happen with property of ObjectA, which holds weak reference to ObjectB? It will become nil, so that it can be safely operated without crashes.
Solution
Now, as we know how memory management works with references, let’s think about Swift implementation. As you remember, in Swift only Optional objects can be nil. It was done for type safety during the development, so that Xcode can warn you at compilation time that something is wrong.
In Swift, new quantifier was also introduced unowned. This keyword tell compiler that, we hold a weak reference, but it’s not an Optional value, so it always should have some value(Similar to unwrapped optionals, which can be nils before first assignment of a value). So, what can go wrong?
Remember code snipper above?
controller.choiceHandler{ [unowned self] (choice) in
self.currentChoice = choice
controller.dismiss(animated: true)
}
self.present(controller, animated: true)
Now, notice that self cannot be nil at the time of execution, so system expects non-nil value. What will happen if you try to access that value when self already dismissed and dealocated? Right, it will crash. Crash mercilessly, without notification. How to handle that? Replace unowned with weak:
controller.choiceHandler{ [weak self] (choice) in
self?.currentChoice = choice
controller.dismiss(animated: true)
}
self.present(controller, animated: true)
Now, self is a weak reference, that can become nil and accessing its value does not violate anything, so system can continue working as usual.
Of course, you have to handle the process, because not saving users choice might be bad mitigation strategy. Or, you should choose other pattern, like:
- Delegate
- Notification
- Shared storage
- etc.
But, at least, you will be safe from crashes, which frightens users like a raid.
So, now you know something more about memory management. Be careful with references.
Good luck.