Is it necessary to use [weak self] in swift network calls?

Consider the following code in a view controller:

func fetchData() {
APIClient.getResultsWithSearchTerm(“food” ) { [weak self](data) in
self?.changeText()
}
}
func changeText() {
titleLabel.text = “finish execute”
}

If the fetchData() network call is being executed, then the view controller is immediately popped from the navigation stack, what difference would it make for having [weak self] in this particular example?

Not much :)

In a couple of tests running this code, the closure in fetchData() is always called after view controller is popped. Sometimes self is nil, and changeText() doesn’t get called. Sometimes self is NOT nil, and changeText() gets called and executed.

Why?

This is mainly due to the async nature of network calls. When the view controller is popped, the deallocation process should begin. At the same time, the network request is happening somewhere waiting for data to return. These two operations are independent of each other. As a result, two scenarios can happen:

  1. Data is returned after view controller is deallocated. Since the view controller object no longer exist, self is nil and changeText() won’t get called.
  2. Data is returned before view controller is deallocated. This is the opposite of scenario #1. self is not nil yet, so it is still valid to execute changeText(). Afterward, the view controller will be deallocated.

There is no guarantee of which scenario will happen. The only difference [weak self] makes here is in scenario #1, the code in changeText() will be optionally skipped. If there is complex logic inside changeText(), may be having this logic skipped will save some processing. Otherwise, the impact of having [weak self] is minimal.

For best practice, use [weak self]. In a rush? Then it’s your call.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.