Работа с JSON в Swift: парсинг и сериализация для начинающих
JSON (JavaScript Object Notation) — это самый популярный формат обмена данными в современных мобильных и веб-приложениях. Если вы разрабатываете под iOS или macOS на Swift, умение парсить и сериализовать JSON — обязательный навык. В этой статье мы разберем все основные способы работы с JSON: от классического JSONSerialization до современного протокола Codable. Материал ориентирован на начинающих разработчиков, которые уже знакомы с основами Swift.
Что такое JSON и зачем он нужен в Swift?
JSON — это текстовый формат, основанный на синтаксисе JavaScript. Он представляет собой пары "ключ-значение", вложенные объекты и массивы. В iOS-разработке JSON используется для:
- Получения данных с REST API серверов
- Сохранения конфигураций и настроек приложения
- Обмена данными между модулями приложения
- Работы с базами данных (например, Firebase или CoreData + JSON)
В Swift есть два основных подхода к работе с JSON: старый способ через JSONSerialization (из Foundation) и современный — с помощью протоколов Codable, Encodable и Decodable. Мы начнем с более простого JSONSerialization, чтобы понять механику, а затем перейдем к мощному Codable.
Парсинг JSON с помощью JSONSerialization (Foundation)
JSONSerialization — это встроенный в Foundation класс, который преобразует JSON-данные в объекты Swift (словари и массивы). Этот метод существует с первых версий Swift и до сих пор используется в легаси-проектах. Давайте разберем пример.
Предположим, у нас есть JSON-строка с информацией о пользователе:
let jsonString = """
{
"name": "Иван",
"age": 30,
"email": "ivan@example.com",
"isActive": true,
"hobbies": ["чтение", "программирование", "спорт"]
}
"""
Чтобы распарсить этот JSON, мы сначала преобразуем строку в данные Data, а затем используем JSONSerialization:
import Foundation
if let jsonData = jsonString.data(using: .utf8) {
do {
if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
print("Имя: \(dictionary["name"] ?? "Нет данных")")
print("Возраст: \(dictionary["age"] ?? "Нет данных")")
if let hobbies = dictionary["hobbies"] as? [String] {
print("Хобби: \(hobbies.joined(separator: ", "))")
}
}
} catch {
print("Ошибка парсинга JSON: \(error.localizedDescription)")
}
}
Важные моменты:
- Всегда используйте
try-catch— парсинг может выбросить ошибку. - Результат приходит как
Any, поэтому нужно приводить к конкретному типу ([String: Any]для объекта,[Any]для массива). - Опции
.mutableContainersи.fragmentsAllowedпозволяют управлять гибкостью парсинга.
Современный подход: протокол Codable
Начиная с Swift 4, Apple представила протокол Codable (объединяет Encodable и Decodable). Это настоящая "магия" — достаточно объявить структуру, и Swift сам знает, как парсить и сериализовать данные. Давайте перепишем предыдущий пример с использованием Codable.
1. Объявление модели данных
struct User: Codable {
let name: String
let age: Int
let email: String
let isActive: Bool
let hobbies: [String]
}
Обратите внимание: названия полей в структуре должны совпадать с ключами JSON (регистр важен). Если ключи отличаются (например, snake_case), используйте CodingKeys.
2. Парсинг JSON в объект Swift
let jsonData = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
do {
let user = try decoder.decode(User.self, from: jsonData)
print("Пользователь: \(user.name), \(user.age) лет")
print("Активен: \(user.isActive)")
print("Хобби: \(user.hobbies)")
} catch {
print("Ошибка декодирования: \(error)")
}
Код стал гораздо чище! Вам не нужно вручную извлекать значения из словаря — все преобразования выполняются автоматически.
3. Сериализация (Swift → JSON)
Обратная операция — преобразование объекта Swift в JSON — выполняется с помощью JSONEncoder:
let newUser = User(
name: "Мария",
age: 25,
email: "maria@example.com",
isActive: false,
hobbies: ["рисование", "путешествия"]
)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // для красивого вывода
do {
let encodedData = try encoder.encode(newUser)
if let jsonStringOutput = String(data: encodedData, encoding: .utf8) {
print(jsonStringOutput)
}
} catch {
print("Ошибка кодирования: \(error)")
}
Результат будет выглядеть так:
{
"name" : "Мария",
"age" : 25,
"email" : "maria@example.com",
"isActive" : false,
"hobbies" : ["рисование", "путешествия"]
}
Продвинутые техники: кастомные ключи и вложенные объекты
В реальных проектах JSON часто приходит с сервера в snake_case (например, first_name), а в Swift принято использовать camelCase (firstName). Для этого используется перечисление CodingKeys и стратегия преобразования ключей.
Использование CodingKeys
struct UserProfile: Codable {
let firstName: String
let lastName: String
let dateOfBirth: String
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case lastName = "last_name"
case dateOfBirth = "date_of_birth"
}
}
Теперь структура будет правильно маппить JSON с сервера.
Автоматическое преобразование snake_case
Если у вас много полей, проще задать глобальную страте