6

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?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
nRewik
  • 8,958
  • 4
  • 23
  • 30
  • 1
    Closures are also reference types like classes. So if you're calling a captured block/closure (lets say from another part of your code and not from the same class), so this closure will have a strong reference to your instance from where it is called. This is why sometimes `[weak self]` is needed so your instance can deallocate later. But by adding `[weak self]` you will have to make sure that your `self` is still there when your closure will execute. For example: `if let weakSelf = self { /* do your work here*/ }`. – DevAndArtist Jul 18 '15 at 05:43
  • Maybe this article will help you to understand it better: http://sketchytech.blogspot.de/2014/09/swift-rules-of-weak-and-unowned.html :) – DevAndArtist Jul 18 '15 at 05:51
  • "Closures are also reference types like classes." Do you have a source for this? – newacct Jul 20 '15 at 22:33
  • While Foo doesn't have a reference to bar, since it's a computer property, you still could assign it say to another instance variable of Foo, and then you would get a reference cycle. So it makes sense to use `[weak self]`. – User Jul 25 '15 at 00:59
  • @newacct - “‘Closures are also reference types like classes.’ Do you have a source for this?” ... I know that’s an old comment, but there’s a section in _The Swift Programming Language_ titled [Closures are Reference Types](https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID104). – Rob Mar 25 '19 at 23:17
  • @Rob: The logic in that section is actually wrong. It only shows that closures capture variables by reference (which was already mentioned in a previous section). A value-type lambda in C++11 that captures a variable by reference would exhibit the same behavior. – newacct Mar 26 '19 at 03:06
  • as long as you're not holding on to a reference to bar, you should be good. If some other class is holding on to bar, as long as your Foo is not holding on to that class, you should be good. If you can, make `var bar` private. If you can't, just make sure you don't have a strong reference to the class using bar (such as delegate...but of course, you have already made all your delegates references weak like you should) – Jacob Mar 26 '19 at 05:35
  • @newacct - The fact that closures are reference types is not the relevant point here, anyway, IMHO. (I was simply trying to provide the documentary evidence that you asked for. Lol.) As Kubee says (and I tried to say in my answer), the only question here is who uses (and potentially maintains a strong reference to) the computed property `bar`. But it ain’t `Foo`, at least in the code provided by the OP. – Rob Mar 26 '19 at 06:08

1 Answers1

3

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].

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Great explanation as always. But one more thing, should I use [weak self] in case of property observers like didSet or willSet, if the property is of the type stored and I am using self inside those observers to call instance method of the class to which property belongs. Ex. greeting property in this https://gist.github.com/BohdanOrlov/bdb64ae4ca83a2fca3af#file-mvvm-swift – ViruMax Nov 22 '20 at 16:58
  • 1
    No, you don't need `[weak self]` pattern in property observers. And I'd remove the `self.` references within the observers, too, as that is just unnecessary syntactic noise. – Rob Nov 22 '20 at 18:00