iOS Interview Question: Synchronous Vs Asynchronous tasks in Swift

Nitin Aggarwal
Swiftable
Published in
4 min readApr 12, 2024

--

Explain the difference between synchronous and asynchronous tasks in Swift. When would you use each?

Synchronous and asynchronous tasks refer to different ways of executing code, each with its own characteristics and use cases.

It’s important to keep the main thread responsive, as a blocked main thread can lead to a poor user experience with an unresponsive or frozen app. Therefore, any tasks that might take some time should be performed asynchronously, allowing the main thread to continue handling user interactions and updating the user interface smoothly.

Synchronous Tasks:

In synchronous tasks, the program waits for a task to complete before moving on to the next line of code. The execution flow is blocked until the task finishes. Synchronous tasks are straightforward to reason about because they execute sequentially, one after the other.

You would typically use synchronous tasks for operations that are quick, non-blocking, and don’t involve any potentially time-consuming operations like network requests. Synchronous tasks are suitable for simple calculations, in-memory data manipulations, or other operations that can be completed quickly without causing any noticeable delay or freezing the user interface. For example:

func synchronousTask() {
print("Swiftable")
print("iOS")
print("Community")
}

synchronousTask()

// Swiftable
// iOS
// Community

In this example, all print functions will be executed in order, one after the other, because each line of code waits for the previous one to complete before executing.

Let’s understand with another example. Let’s define a function that sorts the String’s array in-place using the sort() method. The sort() method is a synchronous operation that rearranges the elements of the array in ascending order based on the default sorting criteria for strings (alphabetical order). For example:

var words = ["swiftable", "developer", "community"]
func sortWords() {
words.sort() // synchronous in-memory sorting
}

sortWords()
print("words: \(words)")
// words: ["community", "developer", "swiftable"]

When we call the sortWords() function, it executes the words.sort() line synchronously on the current thread. This means that the current thread (in this case, the main thread) will block and wait until the sorting operation is completed before moving to the next line of code.

In this case, using a synchronous operation for sorting the in-memory array is acceptable because the operation is likely to be fast and won’t cause any noticeable delay or freezing of the user interface.

Asynchronous Tasks:

In asynchronous tasks, the program does not wait for a task to complete. Instead, it continues executing other tasks while waiting for the asynchronous task to finish. Asynchronous tasks are commonly used for operations that may take some time to complete, such as network requests, file I/O, or animations. For example:

let imageURL = URL(string: "https://example.com/image.jpg")!

let task = URLSession.shared.dataTask(with: imageURL) { data, response, error in
if let data = data, let image = UIImage(data: data) {
DispatchQueue.main.async {
// update downloaded image to UI on the main queue
}
}
}

task.resume() // asynchronous image download

In the above example, the image download operation is performed asynchronously on a background queue, while the main queue remains responsive and able to handle user interactions or other tasks. Once the image data is downloaded, the completion handler is called, and we assign the image on the main queue to ensure smooth UI updates.

By using asynchronous image loading, we prevent the main thread from being blocked during the potentially time-consuming download process, which could cause the user interface to become unresponsive or frozen. This approach ensures a smooth and responsive user experience, even when dealing with network operations or other long-running tasks.

When to Use Each:

  • Synchronous Tasks: Use synchronous tasks when you need to ensure that certain operations are completed sequentially and when the next line of code depends on the result of the previous one. Synchronous tasks are suitable for simple, short-lived operations where blocking the execution flow is acceptable.
  • Asynchronous Tasks: Use asynchronous tasks when you need to perform long-running operations that should not block the execution flow, such as network requests operations that involve waiting for user input. Asynchronous tasks are essential for keeping the UI responsive and for improving overall performance by allowing concurrent execution of tasks.

Swift provides several mechanisms for working with asynchronous tasks, such as Grand Central Dispatch (GCD), Operations, and the modern async/await syntax. These mechanisms allow you to dispatch tasks to background queues or contexts, and handle the results or completion of those tasks asynchronously, ensuring that the main thread remains responsive.

--

--

Nitin Aggarwal
Swiftable

Lead Software Engineer (iOS), Technical Writer, Technical Interviewer, Helping you to crack your iOS interview.