NSError
iPhone App Development
iOS Programming
Swift
Error Handling

How can I use NSError in my iPhone App?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In iOS development, NSError is the Objective-C error representation used widely across Apple frameworks. Swift prefers native Error types, but bridging to NSError remains essential when using Cocoa APIs, legacy code, and interoperability layers. Understanding both models helps you design better error handling and user-facing recovery flows.

Core Structure of NSError

NSError includes:

  • domain string
  • integer code
  • userInfo dictionary for context
swift
1import Foundation
2
3let error = NSError(
4    domain: "com.example.network",
5    code: 1001,
6    userInfo: [NSLocalizedDescriptionKey: "Request timed out"]
7)
8
9print(error.domain)
10print(error.code)
11print(error.localizedDescription)

Domain plus code provides stable machine-readable categorization.

Bridging Between Swift Error and NSError

Any Swift error can be cast to NSError.

swift
1enum AppError: Error {
2    case invalidToken
3}
4
5let swiftError: Error = AppError.invalidToken
6let nsError = swiftError as NSError
7
8print(nsError.domain)
9print(nsError.code)

This is useful for logging and Objective-C API boundaries.

Handling Cocoa API Errors

Many Foundation APIs expose throwing methods or completion handlers that surface NSError semantics.

swift
1import Foundation
2
3do {
4    let url = URL(fileURLWithPath: "/path/that/does/not/exist.txt")
5    _ = try String(contentsOf: url)
6} catch {
7    let nsError = error as NSError
8    print("domain:", nsError.domain)
9    print("code:", nsError.code)
10    print("message:", nsError.localizedDescription)
11}

Inspecting domain and code helps map technical failures to user messages.

User-Friendly Error Mapping

Do not show raw technical text directly. Map internal errors to clear user language.

swift
1func userMessage(for error: NSError) -> String {
2    if error.domain == NSURLErrorDomain && error.code == NSURLErrorNotConnectedToInternet {
3        return "You appear to be offline. Please check your connection."
4    }
5    return "Something went wrong. Please try again."
6}

This keeps UX consistent across app modules.

Logging and Diagnostics

For crash and reliability analysis, log structured fields:

  • domain
  • code
  • operation context
  • request identifier

Structured logs are far more useful than free-form text when investigating incidents.

In privacy-sensitive apps, sanitize userInfo before uploading telemetry.

Designing Custom Error Domains

If you create custom NSError, use reverse-domain naming and stable code values. Keep code meanings documented so server teams, support teams, and analytics dashboards interpret failures consistently.

This prevents long-term ambiguity in multi-team products.

NSError with Completion Handlers

Many Cocoa APIs still surface optional NSError in completion callbacks.

swift
1func fakeRequest(completion: @escaping (Data?, NSError?) -> Void) {
2    let err = NSError(
3        domain: NSURLErrorDomain,
4        code: NSURLErrorTimedOut,
5        userInfo: [NSLocalizedDescriptionKey: "Timed out"]
6    )
7    completion(nil, err)
8}
9
10fakeRequest { data, error in
11    if let e = error {
12        print(e.localizedDescription)
13    }
14}

Understanding this pattern is important when integrating older SDKs in modern Swift codebases.

Converting NSError to Domain-Specific Swift Errors

A practical architecture is to convert raw framework errors into app-specific enums at service boundaries. That keeps UI and business logic independent from low-level domains and codes, while still preserving diagnostic information for logs. This conversion layer improves maintainability as dependencies evolve.

Testing Error Paths

Unit tests should verify domain and code mapping logic, not only localized messages. Stable error classification is crucial for analytics and retry behavior. Add explicit tests for offline, timeout, and authorization scenarios to keep failure handling predictable.

UI Presentation Consistency

Centralize error-to-alert translation in one presenter component so messages, titles, and retry actions are consistent across screens. Consistency reduces user confusion and simplifies localization updates.

Common Pitfalls

  • Treating localized description as stable machine-readable identifier.
  • Exposing raw technical error text directly to end users.
  • Ignoring domain and code and relying on string matching.
  • Mixing inconsistent custom domains across modules.
  • Logging sensitive values from userInfo without redaction.

Summary

  • NSError remains important in iOS interoperability and framework integration.
  • Use domain and code for deterministic error classification.
  • Bridge Swift Error to NSError when needed.
  • Map technical failures to user-friendly messages.
  • Keep error logging structured and privacy-aware.

Course illustration
Course illustration

All Rights Reserved.