Error handling is one of the most important yet overlooked aspects of app development. Let’s explore best practices for Swift.

The Problem with Silent Failures

Nothing frustrates users more than an app that fails silently. “Something went wrong” messages are unhelpful.

Swift’s Error Handling

Swift provides a robust error handling system:

enum NetworkError: Error {
    case invalidURL
    case noData
    case decodingError
    case serverError(Int)
    
    var localizedDescription: String {
        switch self {
        case .invalidURL:
            return "The URL is invalid."
        case .noData:
            return "No data received from the server."
        case .decodingError:
            return "Failed to process the response."
        case .serverError(let code):
            return "Server error: \(code)"
        }
    }
}

Using Result Type

For more flexible error handling:

func fetchUser(id: Int) async -> Result<User, NetworkError> {
    do {
        let user = try await api.getUser(id: id)
        return .success(user)
    } catch let error as NetworkError {
        return .failure(error)
    } catch {
        return .failure(.decodingError)
    }
}

User-Friendly Error Messages

func handleError(_ error: NetworkError) -> String {
    switch error {
    case .invalidURL:
        return "Please check your internet connection and try again."
    case .noData:
        return "We're having trouble loading data. Pull to refresh."
    case .decodingError:
        return "Please update the app to the latest version."
    case .serverError:
        return "Our servers are busy. Please try again in a few minutes."
    }
}

Error handling concept

Good error handling turns frustration into trust. Users appreciate honesty and clarity.