JSONSerialization: what it is, Foundation class methods and how it works

Author: IT Sectr Published: 2026-03-15 Reading time: 8 min

JSONSerialization — a built-in iOS class from the Foundation framework designed for converting JSON to Foundation objects and back. This API is the basic mechanism for working with JSON on Apple platforms without third-party libraries, supporting parsing of dictionaries, arrays, and primitive types. According to Apple Developer, 2024, JSONSerialization supports working with Data, streams, and reading options for flexible JSON data processing.

Key Takeaways

  • JSONSerialization — a built-in Foundation class for parsing JSON on iOS and macOS
  • jsonObject — method for converting JSON Data to Foundation dictionaries and arrays
  • data — method for serializing Foundation objects back to JSON Data
  • isValidJSONObject — validation of whether an object can be serialized to JSON
  • Codable — modern alternative with typed serialization in Swift

What is JSONSerialization

JSONSerialization is a class from the Foundation framework available on iOS, macOS, tvOS, and watchOS. It provides methods for converting JSON Data into Foundation objects (NSDictionary, NSArray, NSString, NSNumber) and back. The class appeared in iOS 5 and until the introduction of Codable (Swift 4) remained the primary way to work with JSON on Apple platforms. Despite its age, JSONSerialization remains relevant in legacy Objective-C projects and in scenarios where dynamic JSON processing is required without a fixed model schema.

When JSONSerialization is used

Despite the advent of Codable, JSONSerialization remains relevant in several scenarios. Dynamic JSON structure — when the response format changes or is unknown in advance — requires accessing dictionaries by keys, which is easier to do through JSONSerialization. The class is also used in Objective-C projects where Codable is not available, and when working with streams for incremental parsing of large JSON files. In tests and mockups, isValidJSONObject and data(withJSONObject:options:) allow quickly generating JSON fixtures without third-party libraries, speeding up development and prototyping.

swift
import Foundation

// Basic structure of using JSONSerialization
let jsonString = """
{
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com"
}
"""

guard let jsonData = jsonString.data(using: .utf8) else {
    return
}

do {
    let json = try JSONSerialization
        .jsonObject(with: jsonData,
                       options: .mutableContainers)
    print(json)
} catch {
    print("JSON parse error: \(error)")
}

Main class methods

JSONSerialization provides four main methods for working with JSON. The main method is jsonObject(with:options:), which converts Data into Foundation objects. The data(withJSONObject:options:) method performs reverse serialization. isValidJSONObject(_:) checks whether an object can be serialized. writeJSONObject(_:to:options:error:) writes JSON directly to a stream. For reading JSON from InputStream, there is the jsonObject(with:options:) method that accepts a stream instead of Data, which is convenient when integrating with network requests that return streaming data.

JSONObject and JSONData

The jsonObject method accepts Data and returns Any — typically NSDictionary or NSArray. For safe usage, the result is cast to the expected type through conditional casting. The data method accepts a Foundation object and returns Data with a JSON representation. The .prettyPrinted option adds indentation formatting for readability.

swift
let jsonString = """
{
    "products": [
        {"id": 1, "name": "iPhone", "price": 999},
        {"id": 2, "name": "iPad", "price": 799}
    ]
}
"""
let data = Data(jsonString.utf8)

if let json = try? JSONSerialization
    .jsonObject(with: data) as? [String: Any],
    let products = json["products"] as? [[String: Any]] {

    for product in products {
        if let name = product["name"] as? String {
            print("Product: \(name)")
        }
    }
}

// Reverse serialization: object -> JSON
let outputDict: [String: Any] = ["status": "ok", "count": 42]
if let outputData = try? JSONSerialization
    .data(withJSONObject: outputDict,
                options: .prettyPrinted) {
    String(data: outputData, encoding: .utf8)
}

JSON parsing examples

Basic parsing of a dictionary with primitive types is the most common operation with JSONSerialization. After receiving Data via URLSession, the developer calls jsonObject and casts the result to the expected type. For arrays of objects, casting to [[String: Any]] is used, after which each element is processed in a loop. This approach is flexible but requires manual type management.

Parsing nested structures

Real APIs return complex nested JSON objects with arrays, dates, and optional fields. JSONSerialization correctly handles any nesting depth, but the developer must independently cast each level to the required type. To simplify this task, Apple recommends using Codable for typed data, and JSONSerialization only for dynamic structures.

swift
// Parsing API response
func parseUserResponse(data: Data) {
    do {
        guard let json = try JSONSerialization
            .jsonObject(with: data) as? [String: Any]
        else { return }

        guard let userId = json["id"] as? Int,
              let name = json["name"] as? String
        else {
            throw ParsingError.missingField
        }

        print("User: \(name) (ID: \(userId))")

    } catch let error as ParsingError {
        print("Parse failed: \(error)")
    } catch {
        print("Unexpected error: \(error)")
    }
}

enum ParsingError: Error {
    case missingField
    case invalidType
}

Error handling

JSONSerialization throws errors on invalid JSON, type mismatches, or exceeding nesting depth. Errors belong to the CocoaError type and contain a code describing the problem. The developer must handle them through a do-catch construct, otherwise the application will crash. The most common errors are: NSPropertyListReadCorruptError (invalid JSON) and NSPropertyListReadUnknownError. Each error type requires its own handling strategy: for invalid format, request data resending, and for structure mismatch, update the parsing model.

Types of deserialization errors

Invalid JSON — the most common cause of failures: a missing comma, extra character, or unescaped quote breaks the entire parsing. The second type of errors is mismatch with the expected structure: for example, the server returned an array instead of a dictionary. JSONSerialization.fragmentsAllowed allows reading JSON whose root is not a dictionary or array but a primitive value. The developer may also encounter a nesting depth exceeded error when JSON contains too many hierarchy levels.

Reading and writing options

JSONSerialization provides several options for configuring parsing. .mutableContainers returns NSMutableDictionary and NSMutableArray instead of immutable versions, which is useful when modifying data after parsing. .mutableLeaves makes string values mutable. .fragmentsAllowed allows JSON whose root is not an object or array but a string or number — convenient for simple API responses. The .withoutEscapingSlashes and .sortedKeys options are available for the data(withJSONObject:options:) method, controlling formatting of serialized JSON. Options are passed as a bitmask, allowing multiple values to be combined via the | operator for flexible parsing configuration.

swift
// Handling various error types
func safeParse(jsonData: Data) {
    do {
        let object = try JSONSerialization
            .jsonObject(with: jsonData,
                           options: .fragmentsAllowed)

        if let dictionary = object as? [String: Any] {
            print("Dictionary with \(dictionary.count) keys")
        } else if let array = object as? [Any] {
            print("Array with \(array.count) items")
        }

    } catch CocoaError.propertyListReadCorrupt {
        print("Corrupt JSON data")
    } catch let error as CocoaError {
        print("Cocoa error: \(error)")
    } catch {
        print("Unknown error: \(error)")
    }
}

// Checking object validity before serialization
let testObject: [String: Any] = ["key": "value", "nested": ["a": 1]]
if JSONSerialization.isValidJSONObject(testObject) {
    print("Valid JSON object")
}

The performance of JSONSerialization depends on the data size and call frequency. For a single parsing of a small server response, the difference is negligible, but when processing tens of megabytes of JSON or frequent calls in loops, overhead from type casting should be considered. JSONSerialization works synchronously in the current thread, so for large documents it is recommended to move parsing to a background queue via DispatchQueue.global(). Alternatively, you can use InputStream for streaming processing without loading the entire file into memory, which is critical for resource-constrained applications. For writing JSON to a file or network stream, the writeJSONObject(_:to:options:error:) method allows directly sending serialized data to OutputStream without creating an intermediate Data object, reducing memory consumption when working with large documents.

Frequently Asked Questions

What is JSONSerialization in iOS?

JSONSerialization is a Foundation class for converting JSON Data into Foundation objects (NSDictionary, NSArray) and back. It works on iOS, macOS, tvOS, and watchOS without additional libraries.

How is JSONSerialization different from Codable?

Codable is a Swift protocol for automatic typed serialization that compiles into type-safe code. JSONSerialization works with dynamic Any types and requires manual casting. Codable is preferable for new projects, JSONSerialization for Objective-C and dynamic data.

How to handle a JSON parsing error?

Use the do-catch construct when calling jsonObject. JSONSerialization errors belong to CocoaError. For debugging, check NSPropertyListReadCorruptError, which indicates an invalid JSON data format.

Does JSONSerialization support nested structures?

Yes, JSONSerialization supports any nesting depth of dictionaries and arrays. All nested objects are converted to corresponding Foundation types (NSDictionary, NSArray, NSString, NSNumber), preserving the original JSON structure.

When to use JSONSerialization instead of Codable?

JSONSerialization is appropriate for dynamic JSON structures, in Objective-C projects, when working with streams, and for validating JSON via isValidJSONObject. For typed structures with a known schema, Codable is preferable.

Summary

  • JSONSerialization — a built-in Foundation class for basic JSON handling on Apple platforms
  • jsonObject — the main parsing method that converts Data into Foundation dictionaries and arrays
  • data — reverse serialization method for Foundation objects into JSON Data with formatting options
  • isValidJSONObject — a predicate for checking whether an object can be serialized to JSON
  • Error handling is mandatory through do-catch to prevent application crashes
  • Codable — a modern typed alternative for Swift projects with a known data schema

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also