Сериализация объектов в Swift (iOS/macOS): Codable, JSON и PropertyList

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Сериализация объектов в 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                    

Рекомендаций