Работа с JSON в Swift: парсинг и сериализация данных

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с JSON в Swift: парсинг и сериализация

JSON (JavaScript Object Notation) стал стандартом де-факто для обмена данными между клиентом и сервером в мобильных и десктопных приложениях. В экосистеме Swift (iOS/macOS) работа с JSON реализована на высшем уровне — от простого JSONSerialization до мощного протокола Codable. В этой статье мы разберём все основные способы парсинга и сериализации JSON в Swift, приведём практические примеры и покажем, как избежать типичных ошибок.

1. Основы работы с JSON в Swift: JSONSerialization

До появления Swift 4 основным инструментом для работы с JSON был класс JSONSerialization, входящий в Foundation. Он позволяет преобразовывать данные JSON в объекты Swift (словари, массивы, строки, числа) и обратно. Этот метод остаётся актуальным, если вам нужен полный контроль над процессом или вы работаете с устаревшим кодом.

Парсинг JSON с помощью JSONSerialization

Предположим, мы получили JSON-строку с сервера:

let jsonString = """
{
    "name": "Иван",
    "age": 30,
    "isPremium": true,
    "hobbies": ["чтение", "бег", "программирование"]
}
"""

guard let jsonData = jsonString.data(using: .utf8) else {
    fatalError("Ошибка кодирования строки в Data")
}

do {
    if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
        let name = jsonObject["name"] as? String ?? ""
        let age = jsonObject["age"] as? Int ?? 0
        let isPremium = jsonObject["isPremium"] as? Bool ?? false
        let hobbies = jsonObject["hobbies"] as? [String] ?? []
        print("Имя: \(name), Возраст: \(age), Премиум: \(isPremium), Хобби: \(hobbies)")
    }
} catch {
    print("Ошибка парсинга JSON: \(error.localizedDescription)")
}

Недостаток этого подхода — необходимость вручную приводить типы и обрабатывать опциональные значения. Код становится громоздким и подвержен ошибкам.

Сериализация в JSON с помощью JSONSerialization

Обратный процесс — превращение словаря Swift в JSON-данные:

let personDict: [String: Any] = [
    "name": "Мария",
    "age": 25,
    "isPremium": false,
    "hobbies": ["рисование", "йога"]
]

do {
    let jsonData = try JSONSerialization.data(withJSONObject: personDict, options: .prettyPrinted)
    if let jsonString = String(data: jsonData, encoding: .utf8) {
        print(jsonString)
    }
} catch {
    print("Ошибка сериализации: \(error.localizedDescription)")
}

Опция .prettyPrinted делает вывод читаемым для человека. Для продакшена обычно используют [] (без форматирования) для экономии трафика.

2. Современный подход: протокол Codable и JSONDecoder

Начиная с Swift 4, работа с JSON стала значительно проще благодаря протоколу Codable (который объединяет Encodable и Decodable). Вы просто описываете структуру данных, и компилятор автоматически генерирует код для кодирования/декодирования.

Парсинг JSON с помощью JSONDecoder

Определим модель для нашего JSON:

struct Person: Codable {
    let name: String
    let age: Int
    let isPremium: Bool
    let hobbies: [String]
}

let jsonString = """
{
    "name": "Иван",
    "age": 30,
    "isPremium": true,
    "hobbies": ["чтение", "бег", "программирование"]
}
"""

guard let jsonData = jsonString.data(using: .utf8) else {
    fatalError("Ошибка кодирования строки")
}

do {
    let person = try JSONDecoder().decode(Person.self, from: jsonData)
    print("Имя: \(person.name), Возраст: \(person.age), Премиум: \(person.isPremium), Хобби: \(person.hobbies)")
} catch {
    print("Ошибка декодирования: \(error.localizedDescription)")
}

Как видите, код стал намного чище. Всё приведение типов и проверки выполняются автоматически. Если JSON не соответствует структуре, вы получите понятную ошибку.

Сериализация в JSON с помощью JSONEncoder

Превратить объект обратно в JSON так же просто:

let person = Person(name: "Мария", age: 25, isPremium: false, hobbies: ["рисование", "йога"])

do {
    let jsonData = try JSONEncoder().encode(person)
    if let jsonString = String(data: jsonData, encoding: .utf8) {
        print(jsonString)
    }
} catch {
    print("Ошибка кодирования: \(error.localizedDescription)")
}

По умолчанию JSONEncoder генерирует компактный JSON без лишних пробелов. Для отладки можно использовать опцию .outputFormatting = .prettyPrinted.

3. Продвинутые техники: кастомные ключи, вложенные объекты и обработка ошибок

В реальных проектах JSON часто приходит с ключами в snake_case, а в Swift принято использовать camelCase. Или же вам нужно пропустить некоторые поля. Codable легко справляется с этими задачами.

Работа с ключами в snake_case

Допустим, сервер возвращает JSON с ключами full_name и is_premium. В Swift мы хотим использовать fullName и isPremium. Для этого нужно определить перечисление CodingKeys:

struct Person: Codable {
    let fullName: String
    let age: Int
    let isPremium: Bool
    let hobbies: [String]

    enum CodingKeys: String, CodingKey {
        case fullName = "full_name"
        case age
        case isPremium = "is_premium"
        case hobbies
    }
}

let jsonString = """
{
    "full_name": "Иван Петров",
    "age": 30,
    "is_premium": true,
    "hobbies": ["чтение", "бег"]
}
"""

// Декодирование работает аналогично предыдущему примеру

Вложенные JSON-объекты

Часто данные имеют вложенную структуру. Codable поддерживает это из коробки:

struct Address: Codable {
    let city: String
    let street: String
}

struct User: Codable {
    let name: String
    let address: Address
}

let jsonString = """
{
    "name": "Анна",
    "address": {
        "city": "Москва",
        "street": "Тверская"
    }
}
"""

let json                

Блоги

Рекомендаций по книгам