SwSwift · Lesson 6 of 8

Errors & async/await

Two things every real app does: handle failures and wait for the network. Swift makes both explicit — throws in the signature, await at the call site.

Swift
enum FileError: Error {
    case notFound(path: String)
    case noPermission
}

func read(file path: String) throws -> String {
    guard path.hasSuffix(".txt") else {
        throw FileError.notFound(path: path)
    }
    return "file contents"
}

// Callers must acknowledge the risk with 'try':
do {
    let text = try read(file: "notes.txt")
    print(text)
} catch FileError.notFound(let path) {
    print("missing: \(path)")
} catch {
    print("other error: \(error)")
}

let maybe = try? read(file: "bad.pdf")   // nil on failure
Swift
// async/await — modern Swift concurrency:
struct User: Codable {
    let login: String
    let name: String?
}

func fetchUser(_ username: String) async throws -> User {
    let url = URL(string: "https://api.github.com/users/\(username)")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

// Run concurrently with async let:
func fetchTwo() async throws {
    async let a = fetchUser("octocat")
    async let b = fetchUser("torvalds")
    let (first, second) = try await (a, b)
    print(first.login, second.login)
}
◆ Note
Codable is Swift's built-in JSON serialization: declare a struct matching the JSON's shape, and encoding/decoding is automatic. Combined with async/await, a typed network call is ~5 lines with zero libraries.