The following figure will help you understand multiple threads:
![](assets/f585c40c-8664-4bdb-bcd4-560737427eee.jpg)
When saveMovie(withName:)is called, we're still on the main thread. The persistence block is opened, the movie is created, its name is set, a helper is created, and then fetchRating(forMovie:callback:) is called on the helper. This call itself is still on the main thread. However, the fetching of data is pushed to a background thread. This was discussed earlier when you experimented with fetching data in a playground.
The callback that's invoked by our dataTask is called on the same thread that the task itself is fetching data on the background thread. We will do what we need to do with the JSON and finally call the callback that was passed to fetchRating(forMovie:callback:). The code inside of this callback is pulled into the background thread and executed there.
You can see that the set movie rating step in the update flow is somehow pushed back to the main thread. This is because of the persist method we added as an extension to the managed object context. The context uses the perform method internally to ensure that any code we execute inside of the persist block is executed on the thread the managed object context is on. Also, since we created the managed object context on the main thread, the movie rating will be set on the main thread.
Threading is a complex subject, but it's essential for building responsive applications. Network logic is a great example of why multithreading is important. If we didn't perform the networking on a separate thread, the interface would be unresponsive for the duration of the request. If you have other operations that might take a while in your app, consider moving them onto a background thread so they don't block the user interface.