Введение в работу с JSON на Swift
JSON (JavaScript Object Notation) — это легкий формат обмена данными, который широко используется в мобильной и веб-разработке. Для начинающих разработчиков на Swift (iOS/macOS) умение работать с JSON — обязательный навык. В этой статье мы разберем два основных подхода: классический JSONSerialization и современный протокол Codable. Вы узнаете, как получать данные из сети, парсить их и преобразовывать обратно в JSON для отправки на сервер.
Независимо от того, создаете ли вы приложение для погоды, список задач или социальную сеть — JSON будет вашим верным спутником. Давайте начнем с простого примера и постепенно перейдем к более сложным сценариям.
Основы JSON в Swift: структура и типы данных
Прежде чем писать код, важно понять, как выглядит JSON. В Swift JSON представлен в виде словарей ([String: Any]) и массивов ([Any]). Основные типы данных в JSON:
- Строки — заключены в двойные кавычки (
"Hello") - Числа — целые и с плавающей точкой (
42,3.14) - Булевы значения —
trueилиfalse - Массивы — упорядоченные списки значений (
[1, 2, 3]) - Объекты — неупорядоченные коллекции пар "ключ-значение" (
{"key": "value"}) - null — пустое значение
В Swift для представления JSON удобно использовать встроенные структуры данных. Рассмотрим пример простого JSON-объекта:
{
"name": "Иван",
"age": 25,
"isStudent": false,
"hobbies": ["чтение", "программирование"]
}
Теперь давайте посмотрим, как работать с этим форматом в коде Swift.
Парсинг JSON с помощью JSONSerialization (классический метод)
До появления протокола Codable разработчики использовали класс JSONSerialization. Этот метод до сих пор актуален, особенно когда структура JSON заранее неизвестна или очень динамична.
Базовый пример парсинга
Предположим, у нас есть JSON-строка, которую нужно преобразовать в объекты Swift:
let jsonString = """
{
"name": "Мария",
"age": 30,
"isEmployed": true
}
"""
if let jsonData = jsonString.data(using: .utf8) {
do {
if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
let name = dictionary["name"] as? String ?? "Неизвестно"
let age = dictionary["age"] as? Int ?? 0
let isEmployed = dictionary["isEmployed"] as? Bool ?? false
print("Имя: \(name), Возраст: \(age), Работает: \(isEmployed)")
}
} catch {
print("Ошибка парсинга JSON: \(error.localizedDescription)")
}
}
Обратите внимание: после получения словаря мы явно приводим каждый элемент к нужному типу. Это может быть неудобно при большом количестве полей.
Работа с массивами в JSON
Часто JSON содержит массивы объектов. Разберем пример с массивом пользователей:
let jsonArrayString = """
[
{"name": "Анна", "age": 22},
{"name": "Петр", "age": 28}
]
"""
if let data = jsonArrayString.data(using: .utf8) {
do {
if let users = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for user in users {
let name = user["name"] as? String ?? ""
let age = user["age"] as? Int ?? 0
print("\(name): \(age) лет")
}
}
} catch {
print("Ошибка: \(error)")
}
}
Метод JSONSerialization прост, но требует много ручного приведения типов. Для современных проектов Apple рекомендует использовать Codable.
Современный подход: протокол Codable
Протокол Codable (объединяет Encodable и Decodable) позволяет автоматически преобразовывать JSON в экземпляры структур или классов и обратно. Это значительно сокращает количество кода и уменьшает вероятность ошибок.
Создание модели данных
Для начала определим структуру, которая соответствует нашему JSON:
struct User: Codable {
let name: String
let age: Int
let isEmployed: Bool?
// isEmployed — опциональное поле (может отсутствовать в JSON)
}
Теперь парсинг становится тривиальным:
let jsonData = """
{
"name": "Сергей",
"age": 35,
"isEmployed": true
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let user = try decoder.decode(User.self, from: jsonData)
print("Пользователь: \(user.name), возраст: \(user.age)")
} catch {
print("Ошибка декодирования: \(error)")
}
Обратите внимание: поле isEmployed объявлено как опциональное (Bool?). Если в JSON оно будет отсутствовать, код не упадет с ошибкой — свойство просто примет значение nil.
Работа с массивами и вложенными объектами
Codable отлично справляется со сложными структурами. Рассмотрим пример с массивом пользователей и вложенным адресом:
struct Address: Codable {
let city: String
let street: String
}
struct Person: Codable {
let name: String
let age: Int
let address: Address
}
let jsonArray = """
[
{"name": "Ольга", "age": 27, "address": {"city": "Москва", "street": "Тверская"}},
{"name": "Дмитрий", "age": 32, "address": {"city": "СПб", "street": "Невский"}}
]
""".data(using: .utf8)!
if let persons = try? JSONDecoder().decode([Person].self, from: jsonArray) {
for person in persons {
print("\(person.name) живет в \(person.address.city)")
}
}
Как видите, вложенные объекты обрабатываются автоматически — достаточно объявить соответствующие вложенные структуры.
Сериализация: преобразование объектов Swift в JSON
Сериализация (