JSONSerialization — вбудований клас iOS з фреймворку Foundation, призначений для перетворення JSON в об’єкти Foundation і навпаки. Цей API є базовим механізмом роботи з JSON на платформах Apple без підключення сторонніх бібліотек, підтримуючи парсинг словників, масивів та примітивних типів. За даними Apple Developer, 2024, JSONSerialization підтримує роботу з Data, потоками та опціями читання для гнучкого оброблення даних JSON.
Головне
JSONSerialization — це клас з фреймворку Foundation, доступний на iOS, macOS, tvOS та watchOS. Він надає методи для перетворення JSON Data в об’єкти Foundation (NSDictionary, NSArray, NSString, NSNumber) та навпаки. Клас з’явився в iOS 5 і до введення Codable (Swift 4) залишався основним способом роботи з JSON на платформах Apple. Незважаючи на вік, JSONSerialization залишається запитуваним в застарілих проектах Objective-C та в сценаріях, де потрібна динамічна обробка JSON без фіксованої схеми моделі.
Незважаючи на появу Codable, JSONSerialization залишається актуальним в кількох сценаріях. Динамічна структура JSON — коли формат відповіді змінюється або невідомий заздалегідь — вимагає доступу до словників за ключами, що легкше зробити через JSONSerialization. Клас також використовується в проектах Objective-C, де Codable недоступний, та при роботі з потоками для покрокового парсингу великих JSON-файлів. У тестах та макетах isValidJSONObject та data(withJSONObject:options:) дозволяють швидко генерувати JSON фікстури без сторонніх бібліотек, прискорюючи розробку та прототипування.
import Foundation
// Базова структура використання JSONSerialization
let jsonString = """
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
"""
guard let jsonData = jsonString.data(using: .utf8) else {
return
}
do {
let json = try JSONSerialization
.jsonObject(with: jsonData,
options: .mutableContainers)
print(json)
} catch {
print("Помилка парсингу JSON: \(error)")
}
JSONSerialization надає чотири основні методи для роботи з JSON. Основний метод — jsonObject(with:options:), який перетворює Data в об’єкти Foundation. Метод data(withJSONObject:options:) виконує зворотну серіалізацію. isValidJSONObject(_:) перевіряє, чи можна серіалізувати об’єкт. writeJSONObject(_:to:options:error:) записує JSON безпосередньо в потік. Для читання JSON з InputStream існує метод jsonObject(with:options:), який приймає потік замість Data, що зручно при інтеграції з мережевими запитами, що повертають потокові дані.
Метод jsonObject приймає Data та повертає Any — звичайно NSDictionary або NSArray. Для безпечного використання результат приводиться до очікуваного типу через умовне приведення. Метод data приймає об’єкт Foundation та повертає Data з JSON-представленням. Опція .prettyPrinted додає форматування з відступами для читабельності.
let jsonString = """
{
"products": [
{"id": 1, "name": "iPhone", "price": 999},
{"id": 2, "name": "iPad", "price": 799}
]
}
"""
let data = Data(jsonString.utf8)
if let json = try? JSONSerialization
.jsonObject(with: data) as? [String: Any],
let products = json["products"] as? [[String: Any]] {
for product in products {
if let name = product["name"] as? String {
print("Продукт: \(name)")
}
}
}
// Зворотна серіалізація: об’єкт -> JSON
let outputDict: [String: Any] = ["status": "ok", "count": 42]
if let outputData = try? JSONSerialization
.data(withJSONObject: outputDict,
options: .prettyPrinted) {
String(data: outputData, encoding: .utf8)
}
Базовий парсинг словника з примітивними типами — найпоширеніша операція з JSONSerialization. Після отримання Data через URLSession розробник викликає jsonObject та приводить результат до очікуваного типу. Для масивів об’єктів використовується приведення до [[String: Any]], після чого кожен елемент обробляється в циклі. Цей підхід гнучкий, але вимагає ручного керування типами.
Справжні API повертають складні вкладені JSON-об’єкти з масивами, датами та опціональними полями. JSONSerialization коректно обробляє будь-яку глибину вкладеності, але розробник повинен самостійно приводити кожен рівень до потрібного типу. Для спрощення цього завдання Apple рекомендує використовувати Codable для типізованих даних, а JSONSerialization — лише для динамічних структур.
// Парсинг відповіді API
func parseUserResponse(data: Data) {
do {
guard let json = try JSONSerialization
.jsonObject(with: data) as? [String: Any]
else { return }
guard let userId = json["id"] as? Int,
let name = json["name"] as? String
else {
throw ParsingError.missingField
}
print("Користувач: \(name) (ID: \(userId))")
} catch let error as ParsingError {
print("Парсинг невдалий: \(error)")
} catch {
print("Несподівана помилка: \(error)")
}
}
enum ParsingError: Error {
case missingField
case invalidType
}
JSONSerialization викидає помилки при недійсному JSON, невідповідності типів або перевищенні глибини вкладеності. Помилки належать до типу CocoaError та містять код з описом проблеми. Розробник повинен обробляти їх через конструкцію do-catch, інакше програма аварійно завершиться. Найпоширеніші помилки: NSPropertyListReadCorruptError (недійсний JSON) та NSPropertyListReadUnknownError. Кожен тип помилки потребує своєї стратегії обробки: при недійсному форматі запитати повторне відправлення даних, а при невідповідності структури оновити модель парсингу.
Недійсний JSON — найпоширеніша причина збоїв: пропущена кома, зайвий символ або неекранована лапки ламають весь парсинг. Другий тип помилок — невідповідність очікуваній структурі: наприклад, сервер повернув масив замість словника. JSONSerialization.fragmentsAllowed дозволяє читати JSON, чиїм коренем є не словник або масив, а примітивне значення. Розробник також може зіткнутися з помилкою перевищення глибини вкладеності, коли JSON містить ззадто багато рівнів ієрархії.
JSONSerialization надає кілька опцій для налаштування парсингу. .mutableContainers повертає NSMutableDictionary та NSMutableArray замість незмінних версій, що корисно при модифікації даних після парсингу. .mutableLeaves робить рядкові значення змінними. .fragmentsAllowed дозволяє JSON, чиїм коренем є не об’єкт або масив, а рядок або число — зручно для простих відповідей API. Опції .withoutEscapingSlashes та .sortedKeys доступні для методу data(withJSONObject:options:), керуючи форматуванням серіалізованого JSON. Опції передаються як бітова маска, що дозволяє комбінувати кілька значень через оператор | для гнучкого налаштування парсингу.
// Обробка різних типів помилок
func safeParse(jsonData: Data) {
do {
let object = try JSONSerialization
.jsonObject(with: jsonData,
options: .fragmentsAllowed)
if let dictionary = object as? [String: Any] {
print("Словник з \(dictionary.count) ключами")
} else if let array = object as? [Any] {
print("Масив з \(array.count) елементів")
}
} catch CocoaError.propertyListReadCorrupt {
print("Пошкоджені дані JSON")
} catch let error as CocoaError {
print("Помилка Cocoa: \(error)")
} catch {
print("Невідома помилка: \(error)")
}
}
// Перевірка валідності об’єкта перед серіалізацією
let testObject: [String: Any] = ["key": "value", "nested": ["a": 1]]
if JSONSerialization.isValidJSONObject(testObject) {
print("Дійсний JSON-об’єкт")
}
Продуктивність JSONSerialization залежить від розміру даних та частоти викликів. Для одноразового парсингу малої відповіді сервера різниця непомітна, але при обробці десятків мегабайтів JSON або частих викликів у циклах варто враховувати накладні витрати на приведення типів. JSONSerialization працює синхронно в поточному потоці, тому для великих документів рекомендується виносити парсинг у фонову чергу через DispatchQueue.global(). Альтернативно можна використовувати InputStream для потокової обробки без завантаження всього файлу в пам'ять, що критично для програм з обмеженими ресурсами. Для запису JSON у файл або мережевий потік метод writeJSONObject(_:to:options:error:) дозволяє напряму відправляти серіалізовані дані в OutputStream без створення проміжного об’єкта Data, що знижує споживання пам'яті при роботі з великими документами.
Часті запитання
JSONSerialization — це клас Foundation для перетворення JSON Data в об’єкти Foundation (NSDictionary, NSArray) та навпаки. Він працює на iOS, macOS, tvOS та watchOS без додаткових бібліотек.
Codable — це протокол Swift для автоматичної типізованої серіалізації, який компілюється в типобезпечний код. JSONSerialization працює з динамічними типами Any та потребує ручного приведення. Codable краще для нових проектів, JSONSerialization — для Objective-C та динамічних даних.
Використовуйте конструкцію do-catch при виклику jsonObject. Помилки JSONSerialization належать до CocoaError. Для налагодження перевірте NSPropertyListReadCorruptError, який вказує на недійсний формат даних JSON.
Так, JSONSerialization підтримує будь-яку глибину вкладеності словників та масивів. Усі вкладені об’єкти перетворюються в відповідні типи Foundation (NSDictionary, NSArray, NSString, NSNumber), зберігаючи первинну структуру JSON.
JSONSerialization доречний для динамічних структур JSON, у проектах Objective-C, при роботі з потоками та для перевірки дійсності JSON через isValidJSONObject. Для типізованих структур з відомою схемою краще обрати Codable.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також