JSON обработка в Swift (iOS/macOS): Полное руководство
JSON (JavaScript Object Notation) — основной формат обмена данными в современных iOS/macOS приложениях. Swift предоставляет мощный набор инструментов для работы с JSON, начиная от встроенных протоколов Codable и заканчивая сторонними библиотеками, упрощающими парсинг и сериализацию. В этой статье мы подробно разберём все основные способы обработки JSON в Swift для платформ Apple.
Встроенная поддержка JSON: Codable (Swift 4+)
Начиная с Swift 4, Apple представила протоколы Codable (объединяющий Encodable и Decodable), которые позволяют автоматически преобразовывать пользовательские типы данных в JSON и обратно без написания boilerplate кода.
Базовый пример декодирования JSON
import Foundation
// 1. Определяем модель данных
struct User: Codable {
let id: Int
let name: String
let email: String
let isActive: Bool
}
// 2. JSON-строка
let jsonString = """
{
"id": 1,
"name": "Иван Петров",
"email": "ivan@example.com",
"isActive": true
}
"""
// 3. Декодируем
if let jsonData = jsonString.data(using: .utf8) {
let decoder = JSONDecoder()
do {
let user = try decoder.decode(User.self, from: jsonData)
print("Пользователь: \(user.name), email: \(user.email)")
} catch {
print("Ошибка декодирования: \(error.localizedDescription)")
}
}
Кодирование объекта в JSON
let newUser = User(id: 2, name: "Мария Сидорова", email: "maria@example.com", isActive: false)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // для читаемого вывода
do {
let jsonData = try encoder.encode(newUser)
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
} catch {
print("Ошибка кодирования: \(error)")
}
Работа с ключами в snake_case и кастомные стратегии
Часто JSON приходит с ключами в стиле snake_case (например, first_name), а Swift-свойства пишутся в camelCase (firstName). Это решается одной строкой:
decoder.keyDecodingStrategy = .convertFromSnakeCase
encoder.keyEncodingStrategy = .convertToSnakeCase
JSONSerialization — низкоуровневая работа
Для случаев, когда структура JSON неизвестна заранее или требуется гибкость, используется JSONSerialization из Foundation:
if let jsonData = jsonString.data(using: .utf8) {
do {
if let jsonDict = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
let name = jsonDict["name"] as? String ?? ""
let age = jsonDict["age"] as? Int ?? 0
print("Имя: \(name), Возраст: \(age)")
}
} catch {
print("Ошибка: \(error)")
}
}
Этот метод возвращает Any, поэтому требуется приведение типов. Подходит для динамических данных, но менее безопасен по типам.
Сторонние библиотеки
Несмотря на мощь встроенных средств, существуют популярные библиотеки, упрощающие работу с JSON в Swift:
1. SwiftyJSON
Одна из самых популярных библиотек. Позволяет обращаться к элементам JSON через подписки (subscripts) и автоматически обрабатывает опциональные значения.
// Установка через Swift Package Manager: https://github.com/SwiftyJSON/SwiftyJSON
import SwiftyJSON
let json = JSON(parseJSON: jsonString)
let userName = json["name"].stringValue
let userEmail = json["email"].string ?? "не указан"
print("Имя: \(userName), Email: \(userEmail)")
// Работа с вложенными объектами
let address = json["address"]["city"].stringValue
2. ObjectMapper
Библиотека для маппинга JSON в объекты и обратно. Требует ручного описания преобразований, но даёт полный контроль.
import ObjectMapper
class UserModel: Mappable {
var id: Int?
var name: String?
required init?(map: Map) {}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
}
}
if let user = UserModel(JSONString: jsonString) {
print(user.name ?? "")
}
3. Codable + Combine (iOS 13+)
Для асинхронной работы с JSON в связке с сетевыми запросами:
import Combine
var cancellables = Set<AnyCancellable>()
let url = URL(string: "https://api.example.com/users")!
URL