Сериализация объектов в Swift (iOS/macOS): Codable, JSON и PropertyList
Сериализация — это процесс преобразования объектов данных в формат, пригодный для хранения или передачи (например, JSON, XML, Property List). В экосистеме Apple (iOS, macOS, watchOS, tvOS) Swift предоставляет мощный и элегантный механизм для сериализации и десериализации — протокол Codable. В этой статье мы подробно разберём, как использовать Codable, JSONEncoder, PropertyListEncoder и их аналоги для работы с данными.
Что такое Codable?
Codable — это составной протокол, объединяющий Encodable (для кодирования объекта в внешний формат) и Decodable (для декодирования из внешнего формата в объект). Если ваша структура или класс Swift соответствует Codable, вы автоматически получаете возможность сериализовать и десериализовать её.
Базовое объявление:
struct User: Codable {
let id: Int
let name: String
let email: String
}
Все стандартные типы Swift (String, Int, Double, Bool, Date, Data, URL и даже опциональные типы и массивы/словари) уже соответствуют Codable.
Кодирование в JSON
Для кодирования объекта в JSON используется JSONEncoder. Пример:
let user = User(id: 1, name: "Иван Петров", email: "ivan@example.com")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // для красивого вывода
do {
let jsonData = try encoder.encode(user)
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
} catch {
print("Ошибка кодирования: \(error)")
}
Результат:
{
"id" : 1,
"name" : "Иван Петров",
"email" : "ivan@example.com"
}
Декодирование из JSON
Для обратного преобразования используется JSONDecoder:
let jsonString = """
{
"id": 2,
"name": "Мария Сидорова",
"email": "maria@example.com"
}
"""
let jsonData = Data(jsonString.utf8)
let decoder = JSONDecoder()
do {
let decodedUser = try decoder.decode(User.self, from: jsonData)
print("Декодирован пользователь: \(decodedUser.name)")
} catch {
print("Ошибка декодирования: \(error)")
}
Работа с Property List (plist)
Для сериализации в формат XML Property List используется PropertyListEncoder и PropertyListDecoder. Это полезно для хранения данных в файлах конфигурации или UserDefaults.
// Кодирование в plist
let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
do {
let plistData = try encoder.encode(user)
// plistData можно сохранить в файл или UserDefaults
} catch {
print("Ошибка кодирования plist: \(error)")
}
// Декодирование из plist
let decoder = PropertyListDecoder()
do {
let decodedUser = try decoder.decode(User.self, from: plistData)
print(decodedUser)
} catch {
print("Ошибка декодирования plist: \(error)")
}
Кастомные ключи (CodingKeys)
Иногда имена свойств в Swift не совпадают с ключами в JSON. Для этого используется перечисление 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
}
}
Теперь JSON с ключами product_id и product_name будет корректно обработан.
Обработка дат и других специальных типов
По умолчанию JSONEncoder и JSONDecoder кодируют даты как TimeInterval (количество секунд с 1970 года). Вы можете изменить стратегию:
struct Event: Codable {
let title: String
let date: Date
}
let event = Event(title: "Конференция", date: Date())
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601 // ISO 8601 формат
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
Другие стратегии: .formatted(DateFormatter), .custom(...).
Сериализация массивов и словарей
Массивы и словари, содержащие Codable элементы, также поддерживают сериализацию:
let users