SyntaxStudy
Sign Up
Swift Multiple Error Types and Typed Throws
Swift Beginner 1 min read

Multiple Error Types and Typed Throws

When a function can throw multiple error types, callers must be prepared to handle any of them. Swift 6 introduces typed throws — throws(MyError) — allowing the compiler to know the exact error type without boxing in any Error. Error hierarchies using protocols let you group related errors. You can catch a protocol type to handle a family of errors uniformly. The defer statement executes a block when the current scope exits (whether normally or via throw), enabling reliable cleanup similar to try-finally in other languages.
Example
import Foundation

// Error hierarchy with protocol
protocol AppError: LocalizedError {
    var code: Int { get }
}

struct DatabaseError: AppError {
    let code: Int
    let message: String
    var errorDescription: String? { "DB[\(code)]: \(message)" }
}

struct NetworkError2: AppError {
    let code: Int
    let statusCode: Int
    var errorDescription: String? { "Network[\(code)]: HTTP \(statusCode)" }
}

// defer for cleanup
func readFile(at path: String) throws -> String {
    let handle = try FileHandle(forReadingAtPath: path) ?? { throw NSError(domain: "FileError", code: 1) }()
    defer { handle.closeFile() }  // always runs on exit

    guard let data = try handle.readToEnd(),
          let content = String(data: data, encoding: .utf8) else {
        throw NSError(domain: "FileError", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot decode file"])
    }
    return content
}

// Catching by protocol type
func performAppOperation() throws {
    throw DatabaseError(code: 5001, message: "Connection refused")
}

do {
    try performAppOperation()
} catch let error as any AppError {
    print("App error \(error.code): \(error.localizedDescription)")
} catch {
    print("Unknown: \(error)")
}