Understanding Async and Async in Swift

This article will help you grasp the differences between Sync and Async operations in Swift

article

What is Synchronous Execution?


Synchronous execution is the simplest and most straightforward way to run code. In this mode, tasks are executed one after the other, in a sequential order. Imagine a single-lane road where each car must wait for the one in front of it to move before it can proceed. This is how synchronous code behaves—each line of code waits for the previous one to finish before it starts.


For example, consider the following Swift code that downloads data from a URL:



func fetchData() -> Data? {
    let url = URL(string: "https://example.com/data")!
    let data = try? Data(contentsOf: url)
    return data
}
let data = fetchData()
// Process the data

In this example, the function fetchData() runs synchronously. It waits until the data is fully downloaded before returning and allowing the rest of the code to execute. This can be problematic if the data takes a long time to download, as it would block the main thread, making the app unresponsive during the download.


What is Asynchronous Execution?


Asynchronous execution, on the other hand, allows tasks to run independently of each other. Imagine the same single-lane road, but now some cars can temporarily drive off-road to bypass traffic and continue on their way. In programming, this means that while one task is waiting (like downloading data), other tasks can proceed without being blocked.


Asynchronous execution is crucial in scenarios where tasks may take a considerable amount of time, such as network requests, database operations, or file processing. In Swift, you can handle asynchronous tasks using completion handlers, closures, or the more modern async/await syntax introduced in Swift 5.5.


Why Asynchronous Code Matters


In iOS development, most tasks that interact with external resources, like fetching data from the internet or accessing the file system, should be performed asynchronously. This ensures that your app remains responsive to user interactions, even while handling time-consuming operations.


For example, if your app needs to download an image from a remote server, doing this synchronously would cause the app to freeze until the download is complete. With asynchronous execution, you can start the download and continue updating the user interface, responding to user inputs, or performing other tasks while the download is in progress.


Here’s how you can modify the earlier example to fetch data asynchronously using Swift’s modern concurrency features:



func fetchData() async -> Data? {
    let url = URL(string: "https://example.com/data")!
    do {
        let (data, _) = try await URLSession.shared.data(from: url)
        return data
    } catch {
        print("Failed to fetch data")
        return nil
    }
}
Task {
let data = await fetchData()
// Process the data
}

In this asynchronous version, the fetchData() function returns immediately, and the actual network request runs in the background. The await keyword tells Swift to wait for the data to be fetched without blocking the rest of the code. This way, your app remains responsive, and the data is processed as soon as it’s available.


The Benefits of Asynchronous Programming


By using asynchronous execution, you can significantly improve the performance and user experience of your applications. Here are some of the key benefits:


  • Your app remains responsive to user interactions even while performing long-running tasks.
  • You can perform multiple tasks simultaneously, making better use of the device’s resources.
  • Asynchronous code can be more efficient, as it allows you to handle tasks as soon as their results are available.

Conclusion


Understanding the difference between synchronous and asynchronous execution is crucial for building efficient and responsive applications. In Swift, asynchronous execution is made easier with the async/await syntax, allowing you to write code that is both readable and performant. By incorporating asynchronous practices into your development workflow, you can ensure that your apps provide a smooth and enjoyable experience for users.


Synchronous execution runs tasks one after the other, potentially blocking the app’s main thread, while asynchronous execution allows tasks to run independently, keeping the app responsive. Swift’s async/await syntax simplifies writing asynchronous code, improving both performance and user experience.

instructor

Exodai INSTRUCTOR!

Johan t'Sas

Owner and Swift developer!