NSJSONSerialization
JSON
iOS development
Swift programming
Objective-C

How to use NSJSONSerialization

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

NSJSONSerialization (now JSONSerialization in Swift) converts between JSON data and Foundation objects (Dictionary, Array, String, Number). It provides jsonObject(with:) to parse JSON Data into Foundation objects, and data(withJSONObject:) to serialize Foundation objects into JSON Data. While Codable (Swift 4+) is now the preferred approach for type-safe JSON handling, JSONSerialization remains useful for dynamic JSON structures, quick prototyping, and Objective-C compatibility.

Parsing JSON Data to Dictionary

swift
1import Foundation
2
3let jsonString = """
4{
5    "name": "Alice",
6    "age": 30,
7    "email": "[email protected]",
8    "hobbies": ["reading", "coding", "hiking"]
9}
10"""
11
12let jsonData = jsonString.data(using: .utf8)!
13
14do {
15    if let dict = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] {
16        let name = dict["name"] as? String ?? ""
17        let age = dict["age"] as? Int ?? 0
18        let hobbies = dict["hobbies"] as? [String] ?? []
19
20        print("Name: \(name)")    // Alice
21        print("Age: \(age)")      // 30
22        print("Hobbies: \(hobbies)")  // ["reading", "coding", "hiking"]
23    }
24} catch {
25    print("JSON parsing error: \(error.localizedDescription)")
26}

jsonObject(with:) returns Any — you must cast to the expected type ([String: Any] for objects, [Any] for arrays). Every nested value also requires type casting.

Parsing a JSON Array

swift
1let jsonArrayString = """
2[
3    {"id": 1, "name": "Alice"},
4    {"id": 2, "name": "Bob"},
5    {"id": 3, "name": "Charlie"}
6]
7"""
8
9let data = jsonArrayString.data(using: .utf8)!
10
11do {
12    if let array = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] {
13        for item in array {
14            let id = item["id"] as? Int ?? 0
15            let name = item["name"] as? String ?? ""
16            print("\(id): \(name)")
17        }
18    }
19} catch {
20    print("Error: \(error)")
21}

Serializing Dictionary to JSON Data

swift
1let userDict: [String: Any] = [
2    "name": "Alice",
3    "age": 30,
4    "active": true,
5    "scores": [95, 87, 92],
6]
7
8do {
9    let jsonData = try JSONSerialization.data(withJSONObject: userDict, options: .prettyPrinted)
10    if let jsonString = String(data: jsonData, encoding: .utf8) {
11        print(jsonString)
12    }
13} catch {
14    print("Serialization error: \(error)")
15}
16
17// Output:
18// {
19//   "name" : "Alice",
20//   "age" : 30,
21//   "active" : true,
22//   "scores" : [95, 87, 92]
23// }

options: .prettyPrinted formats the output with indentation. For compact output (APIs), omit the option or pass [].

Validating JSON

swift
1// Check if an object can be serialized to JSON
2let validObject: [String: Any] = ["key": "value", "number": 42]
3let invalidObject: [String: Any] = ["key": Date()]  // Date is not JSON-serializable
4
5print(JSONSerialization.isValidJSONObject(validObject))   // true
6print(JSONSerialization.isValidJSONObject(invalidObject))  // false
7
8// Valid JSON types: String, Number (Int, Double), Bool, Array, Dictionary, NSNull

isValidJSONObject() checks if the object graph contains only JSON-compatible types before attempting serialization.

Network Request Example

swift
1func fetchUser(completion: @escaping ([String: Any]?) -> Void) {
2    let url = URL(string: "https://api.example.com/user/1")!
3
4    URLSession.shared.dataTask(with: url) { data, response, error in
5        guard let data = data, error == nil else {
6            print("Network error: \(error?.localizedDescription ?? "unknown")")
7            completion(nil)
8            return
9        }
10
11        do {
12            let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
13            completion(json)
14        } catch {
15            print("JSON error: \(error)")
16            completion(nil)
17        }
18    }.resume()
19}
20
21// Usage
22fetchUser { user in
23    if let name = user?["name"] as? String {
24        print("User: \(name)")
25    }
26}

Codable Alternative (Preferred in Modern Swift)

swift
1// Codable provides type safety without manual casting
2struct User: Codable {
3    let name: String
4    let age: Int
5    let email: String
6    let hobbies: [String]
7}
8
9let jsonData = jsonString.data(using: .utf8)!
10
11// Decode
12let user = try JSONDecoder().decode(User.self, from: jsonData)
13print(user.name)  // Alice
14
15// Encode
16let encoded = try JSONEncoder().encode(user)
17let jsonOutput = String(data: encoded, encoding: .utf8)!
18
19// When to use JSONSerialization vs Codable:
20// JSONSerialization: dynamic JSON, unknown structure, Objective-C code
21// Codable: known structure, type safety, Swift-only code

Reading/Writing Options

swift
1// Reading options
2let options: JSONSerialization.ReadingOptions = [
3    .mutableContainers,    // Returns mutable arrays/dictionaries
4    .mutableLeaves,        // Returns mutable strings
5    .fragmentsAllowed,     // Allows top-level non-object/array (e.g., "hello" or 42)
6]
7
8// Writing options
9let writeOptions: JSONSerialization.WritingOptions = [
10    .prettyPrinted,        // Formatted output
11    .sortedKeys,           // Alphabetical key order (iOS 11+)
12    .fragmentsAllowed,     // Allow top-level non-object/array
13]
14
15let data = try JSONSerialization.data(
16    withJSONObject: dict,
17    options: [.prettyPrinted, .sortedKeys]
18)

Common Pitfalls

  • Excessive type casting: Every value from JSONSerialization is Any and requires manual as? casting. This is verbose and error-prone for complex JSON. Use Codable for known structures.
  • Non-serializable types: Date, URL, custom objects, and Data cannot be serialized by JSONSerialization. Convert them to strings or numbers first, or use Codable with custom encode methods.
  • Force unwrapping crashes: dict["key"] as! String crashes if the key is missing or the type is wrong. Always use as? with optional binding or default values.
  • Fragments not allowed by default: Top-level JSON values like "hello" or 42 (not objects or arrays) cause errors without .fragmentsAllowed. Add this option if your API returns non-object responses.
  • Key ordering not guaranteed: Dictionary keys in JSON output are unordered by default. Use .sortedKeys (iOS 11+) if you need deterministic output for testing or caching.

Summary

  • JSONSerialization.jsonObject(with: data) parses JSON data into Foundation objects
  • JSONSerialization.data(withJSONObject: obj) serializes Foundation objects to JSON data
  • Use isValidJSONObject() to verify objects contain only JSON-compatible types before serializing
  • Every parsed value is Any — use as? casting for type safety
  • Prefer Codable (JSONDecoder/JSONEncoder) for type-safe JSON handling in modern Swift
  • JSONSerialization remains useful for dynamic JSON and Objective-C interoperability

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions