I see a lot of code like this:
DispatchQueue.main.async {
self.tableView.reloadData()
}
In this context, where tableView
is a property of self
, should one instead ensure weak self
is captured like this:
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
I think so, but this type of "unsafe" code is so ubiquitous across codebases I wonder if I'm missing something?
You said:
In this context, where
tableView
is a property ofself
, should one instead ensureweak self
is captured like this:DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() }
No, you don’t actually need to use weak
reference to self
in this case. There is no persistent strong reference cycle here. The worst that would happen (in the absence of weak
reference) is that it will keep a strong reference to self
until the dispatched block finishes running. But that closure will generally run practically immediately and the fleeting strong reference will be eliminated very quickly.
So, as such, no, you don’t have to use weak
reference here. It is not technically incorrect to do so, but adds a syntactic noise for practically no benefit. Yes, we should be diligent about breaking potential strong reference cycles with weak
references, but this is not one of those cases.
By the way, the choice of the term “unsafe” muddles the topic a bit. “Unsafe” has a very specific meaning when talking about memory references: It generally refers to dangling references to deallocated objects when not using runtime safety checks. As The Swift Programming Language: Automatic Reference Counting says (emphasis from original):
Swift also provides unsafe unowned references for cases where you need to disable runtime safety checks—for example, for performance reasons. As with all unsafe operations, you take on the responsibility for checking that code for safety.
You indicate an unsafe unowned reference by writing
unowned(unsafe)
. If you try to access an unsafe unowned reference after the instance that it refers to is deallocated, your program will try to access the memory location where the instance used to be, which is an unsafe operation.
Obviously, both strong and weak references are safe (the former keeps the object from being released, the latter sets its references to nil
when the object is deallocated). Even unowned
references often employ runtime safety checks (though it still results in runtime error if you use a unowned
reference after the object is deallocated). An “unsafe” reference is used in high-performance scenarios, where you are absolutely confident in your unowned references are being handled properly and that you’re willing to run your code without runtime safety checks.
I suspect you didn’t mean “unsafe” in this context, but I mention it so that you are aware of the very specific meaning that this word has within the context of ARC and memory management.