Weak self reference vs strong member reference performance

What are the tradeoffs between capturing self weakly vs capturing a member on self strongly. Are there performance tradeoffs for strong vs weak captures?

Given the class below, are options 1 and 2 equivalent, or are there some tradeoff between the two?

final class Foo {
  let bar: Bar
  let networkService: NetworkService

  // Option 1
  func option1() {
    networkService.performSomeRequest { [weak self] data in
        self?.bar.handleData(data)
    }
  }

  // Option 2
  func option2() {
    networkService.performSomeRequest { [bar] data in
        bar.handleData(data)
    }
  }
}

There are some performance differences (explained below), but I don't think they're something to worry about unless it proves to be an issue.

I prefer strongly capturing the members I need, because there are more cases where I store a self-capturing closure into self, than cases where I would store bar-capturing closures into bar, so I find it to be a natural way to reduce accidental cycles.

However, that's only possible when bar is constant. If you want it to be immutable, you end up needing to capture self.

The perf differences

Weakly referenced objects need one extra memory allocation, and have more indirection when accessing their class/ref-count. If you're curious for more details, I'd recommend Mike Ash's article Friday Q&A 2017-09-22: Swift 4 Weak References

1 Like

Does handleData do anything useful if self was already deallocated? I think deciding whether you want to execute handleData in such cases has bigger performance impact than weak vs strong capture.

3 Likes

Weak references definitely incur some performance overhead, but I'd strongly encourage not worrying about it unless a profiling tool like Instruments says you should. IMO the key thing with weak references is understanding your object graph and using them consciously with specific intent rather than just sprinkling them in and hoping for the best.

If you're in the rare situation where a weak reference is both semantically necessary and a source of significant overhead, we can help brainstorm alternatives.

6 Likes