JSON обработка в Swift: Codable, JSONSerialization и практические примеры

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

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

Начать курс

JSON обработка в Swift (iOS/macOS): от основ до продвинутого использования

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

1. Основы: протокол Codable

Протокол Codable — это комбинация Encodable и Decodable. Он автоматически генерирует код для преобразования ваших структур и классов в JSON и обратно. Это основной и рекомендуемый способ работы с JSON в современном Swift.

1.1. Простая модель данных

import Foundation

struct User: Codable {
    let id: Int
    let name: String
    let email: String
    let isActive: Bool
}

// Пример JSON строки
let jsonString = """
{
    "id": 1,
    "name": "Иван Петров",
    "email": "ivan@example.com",
    "isActive": true
}
"""

// Декодирование
if let jsonData = jsonString.data(using: .utf8) {
    let decoder = JSONDecoder()
    if let user = try? decoder.decode(User.self, from: jsonData) {
        print("Пользователь: \(user.name), email: \(user.email)")
    }
}

1.2. Кастомные ключи (CodingKeys)

Если ключи в JSON отличаются от свойств модели (например, snake_case в JSON, camelCase в Swift), используйте перечисление CodingKeys:

struct Product: Codable {
    let productId: Int
    let productName: String
    let price: Double

    enum CodingKeys: String, CodingKey {
        case productId = "product_id"
        case productName = "product_name"
        case price
    }
}

let jsonProduct = """
{
    "product_id": 101,
    "product_name": "MacBook Pro",
    "price": 2499.99
}
"""

2. Работа с массивами и вложенными объектами

JSON часто содержит массивы объектов или вложенные структуры. Codable справляется с этим без труда:

struct Author: Codable {
    let name: String
    let books: [Book]
}

struct Book: Codable {
    let title: String
    let year: Int
}

let jsonLibrary = """
{
    "name": "Джоан Роулинг",
    "books": [
        {"title": "Гарри Поттер и философский камень", "year": 1997},
        {"title": "Гарри Поттер и Тайная комната", "year": 1998}
    ]
}
"""

if let data = jsonLibrary.data(using: .utf8) {
    let author = try? JSONDecoder().decode(Author.self, from: data)
    print("Автор: \(author?.name ?? ""), книг: \(author?.books.count ?? 0)")
}

3. JSONSerialization — низкоуровневый подход

Хотя Codable — предпочтительный способ, иногда нужно работать с динамическими или неструктурированными данными. В таких случаях используйте JSONSerialization из Foundation:

let jsonString = """
{
    "status": "success",
    "data": {
        "temperature": 22.5,
        "humidity": 65,
        "city": "Москва"
    }
}
"""

if let data = jsonString.data(using: .utf8) {
    do {
        if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
            if let status = json["status"] as? String {
                print("Статус: \(status)")
            }
            if let dataDict = json["data"] as? [String: Any],
               let temp = dataDict["temperature"] as? Double {
                print("Температура: \(temp)°C")
            }
        }
    } catch {
        print("Ошибка парсинга JSON: \(error.localizedDescription)")
    }
}

4. Обработка ошибок и опциональные значения

Реальные JSON-данные часто содержат отсутствующие поля или null. В Swift это обрабатывается через опциональные свойства (?) и механизм try/catch:

struct Response: Codable {
    let code: Int
    let message: String?
    let data: UserData?
}

struct UserData: Codable {
    let id: Int
    let nickname: String?
}

let jsonWithNull = """
{
    "code": 200,
    "message": null,
    "data": {
        "id": 42,
        "nickname": null
    }
}
"""

do {
    let response = try JSONDecoder().decode(Response.self, from: Data(jsonWithNull.utf8))
    print("Код: \(response.code), никнейм: \(response.data?.nickname ?? "не указан")")
} catch {
    print("Ошибка декодирования: \(                    

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