0% found this document useful (0 votes)
6 views7 pages

Swift Async-Await Explained Simply

Uploaded by

kabindra.karkii
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views7 pages

Swift Async-Await Explained Simply

Uploaded by

kabindra.karkii
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

🚀 Async-Await in Swift

Explained Like You're Chatting with a Teammate


"Imagine ordering pizza online 🍕. You place the order and then… you don’t
just stare at the app until it arrives, right? You continue watching your show,
and the delivery guy calls when he’s outside. That’s exactly what async-
await is like in Swift."

🧠 Why Async/Await?
Before Swift 5.5, writing async code in Swift felt like nesting dolls of closures — a
callback inside a callback inside a callback... and oh wait, another callback 😅. Enter
async/await, Swift's solution for clearer, more readable concurrency — a total game
changer for modern iOS development.

🧩 What is async?
When you mark a function as async, you're telling Swift:
“Hey, this function might take a while to finish — like a network call or image
download — so don’t block the rest of the app.”

👇 Example:
func fetchImages() async throws -> [UIImage] {
// Imagine this calls an API and gets images
}

Think of it like saying:


📦 “This function will deliver a package later — wait for it!”

🕐 What is await?
await is the magic keyword that lets us pause execution until an async function
finishes.

🧪 Try-Catch Example:
do {
let images = try await fetchImages()
print("We got \([Link]) images!")
} catch {
print("Oops! Something went wrong: \(error)")
}

Real-life analogy: You’ve ordered coffee ☕ at Starbucks. await is you waiting for your

name to be called. You don’t go back to the counter every second asking, “Is it done
yet?”

🤯 Before vs After: Async vs Closure


👎 Old-School Completion Handlers:
func fetchImages(completion: @escaping (Result<[UIImage], Error>) ->
Void) {
// code with lots of nested closures 😩
}

Closures used to be our go-to for async work — but they made code harder to follow,
often leading to callback hell. Also:

● You had to remember to call the completion block at every exit point.

● You couldn't use try/catch easily.

● You had to unwrap optionals manually.

👍 The Async Way:


let images = try await fetchImages()

Clean. Simple. No mess. ✨


Structured Concurrency: Why It Matters
Structured concurrency lets us write async code sequentially, just like synchronous
code — making it easy to read and reason about.

🎯 Compare These Two:


Old (Closure Nesting):

fetchImages { result in
switch result {
case .success(let images):
resizeImages(images) { resizedResult in
// And the chain continues...
}
}
}

New (Async/Await):

do {
let images = try await fetchImages()
let resized = try await resizeImages(images)
print("Resized \([Link]) images!")
} catch {
print("Something failed.")
}

No more pyramid of doom. Just clean, top-down logic. 🧼

🛠 Common Error: Calling await in Sync Code


You may hit this:

❌ "'async' call in a function that does not support concurrency"


This happens when you're trying to await inside a normal function. Fix?

✅ Wrap in a Task:
func fetchData() {
Task { @MainActor in
do {
[Link] = try await fetchImages()
} catch {
print("Failed to fetch images")
}
}
}

💡 Use @MainActor if you're updating UI-bound properties.

🧬 Refactoring Old Code


If you're migrating a legacy codebase, you’ve got options:

1. Convert to Async Only:


func fetchImages() async throws -> [UIImage] { ... }

2. Add Async Alternative (Keep Old Too):


@available(*, deprecated, renamed: "fetchImages()")
func fetchImages(completion: ...) { ... }

func fetchImages() async throws -> [UIImage] { ... }

3. Async Wrapper with Continuation:


func fetchImages() async throws -> [UIImage] {
return try await withCheckedThrowingContinuation { continuation
in
fetchImages { result in
[Link](with: result)
}
}
}

Think of continuation as a bridge from the old world (callbacks) to the new async city 🌆.

🧯 Common Gotchas
🚫 Capturing self in Concurrent Code
If you see:

"Reference to captured parameter ‘self’ in concurrently-executing code"

You might be mutating a let variable or using self in a struct. Fix by:

● Making it var
● Or switching to a class

🧐 Do We Still Need Result?


Once you're deep in async-await, you may not need Result anymore. try/catch
replaces it beautifully. But Result is still useful for completion handlers or legacy
frameworks.

🧠 Real-Life Use Cases


1. Image Loading in UICollectionView:

Task {
[Link] = try? await [Link](url)
}

2. Firebase or REST API Calls:

let user = try await [Link]().signIn(...)

3. Parallel Tasks using async let:


async let image1 = fetchImage1()
async let image2 = fetchImage2()
let both = try await [image1, image2]

🎯 Summary

● async declares work that might take time.


● await pauses until that async work completes.

● Structured concurrency = cleaner, simpler async code.

● Wrap await calls in Task if your function isn’t async.

● Use try/catch instead of Result.

💬 In Your Own Words


If someone asks:

"Why should I use async/await?"

You say:

"Because it makes your code cleaner, safer, and easier to follow — just like
reading instructions instead of solving a puzzle blindfolded."

You might also like