I am confused about using self
inside a closure.
When should we declare [weak self]
? An obvious case that I understand is
class Foo{
var closure: ( Void -> Void )?
var x = 0
func doSomething(){
closure = { [weak self] in
if let x = self?.x{
println(x)
}
}
}
}
However, if I want to create a computed property bar
, which it has a closure, and it captures self inside. Like this,
extension Foo{
var bar: Bar{
let bar = Bar()
bar.completionHandler = {
println(self.x)
}
return bar
}
}
Should I use [weak self]
inside this closure?
Consider:
extension Foo {
var bar: Bar {
let bar = Bar()
bar.completionHandler = {
print(self.x)
}
return bar
}
}
Should I use
[weak self]
inside this closure?
Usually when people ask this question, the real concern is “do I need [weak self]
to avoid strong reference cycle?” The answer to that is, no, there is no strong reference cycle here.
If bar
were a stored property, the absence of [weak self]
would raise red flags. It could easily be problematic if we had a Foo
that stored a reference to a Bar
which, itself, had a closure with a self
reference back to the original Foo
. But with this computed property, Foo
doesn’t have any strong reference to bar
, so the strong reference cycle concerns are largely diminished.
That having been said, I have a hard time imaging where I wouldn’t want to use [weak self]
. If bar
has a completionHandler
, that means it’s likely used in some asynchronous scenario, and the question is whether Foo
needs to be retained during this process.
So, the real question of “should” you use [weak self]
comes down to what Bar
is, and whether it has any reasonably claim of ownership over Foo
.
Let’s try to come up with a practical example. (The following is a bit contrived, because I have a hard time imaging a good use-case for this pattern, but bear with me.)
For example, let’s assume that Foo
was a Person
object and Bar
was some URLSessionTask
for the image download task:
class Person {
let name: String
private(set) var image: UIImage?
...
}
extension Person {
var imageTask: URLSessionTask {
let url = ...
return session.dataTask(with: url) { [weak self] data, _, _ in
guard let data = data, let image = UIImage(data: data) else { return }
self?.image = image
}
}
}
So a controller might say
let person = Person(...)
let task = person.imageTask
task.resume()
In the above example, I happened to use [weak self]
in imageTask
closure, not because I was worried about any strong reference cycle, but simply because a network task generally has no business claiming a strong reference over the model object. (Then, again, I wouldn’t personally bury network interfaces in model objects, either.) But in this example, one could omit [weak self]
reference for this closure if, for example, you wanted to make sure that the Person
object was retained until the network request was done (e.g. maybe you wanted to save the results of the network request in some local persistent storage).
All of this having been said, I have a really hard time imaging where I would use the above pattern at all. But the bottom line is that there is no strong reference cycle here, so you theoretically could omit the [weak self]
without concern. But in most practical scenarios, you generally would end up using [weak self]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With