TL;DR: I have an IBOutlet
(UILabel
) that is properly connected in Storyboard. Accessing (unwrapping) it works fine in viewDidLoad()
... but a few seconds later its value is nil. A watchpoint says that the outlet changes right after a call to viewDidLayoutSubviews()
, but... a print()
call at the end of viewDidLayoutSubviews()
shows it non-nil.
This is very similar to IBOutlet is nil but his solution (track value with didSet()
) did not work. (There are many related posts but all had trivial solutions.)
What I have done:
- Reconnected the outlet to the Label — from both sides
- Deleted the Label and reconnected it
- Cleaned the project
- Deleted the DerivedData
- Quit and restarted Xcode
- Quit and restarted my Mac
- Added a
didSet()
method to the outlet.- It triggers during
viewDidLoad()
and shows a non-nil value. - In
viewDidLoad()
I set its text value with no problem - It does not trigger before the nil-unwrapping crash
- It triggers during
- Added a watchpoint to the variable.
- This does trigger before crash (right after
viewDidLayoutSubviews()
and shows the following:
- This does trigger before crash (right after
As mentioned before, at exit of the most recent method call before the watchpoint (viewDidLayoutSubviews()
) the outlet is non-nil.
These crashes seem always to involve subviews of a particular superview. I added a watchpoint to the superview's outlet but it never triggers.
What could be inciting my code to let go of this weak reference?
TL;DR: I was clobbering the relevant views.
Well, the best way to find your own answer is to ask someone else. Thanks to @DonMag, I was preparing more traces, breakpoints, and screen shots. I noticed this method (added to fix another bug, of course):
Of course, the two views that were becoming nil were subviews of
centralOverlay
. Ones I wanted to keep.So I guess my answer was similar to that of IBOutlet is nil — pilot error — except the
didSet()
handler did not solve the mystery.