SwiftyJSON для Swift: полное руководство с примерами

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

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

Начать курс

SwiftyJSON для Swift: полное руководство с примерами

1. Что это и зачем нужна

SwiftyJSON — это легковесная библиотека для языка Swift, которая кардинально упрощает работу с JSON-данными. В стандартном Swift работа с JSON через JSONSerialization требует большого количества шаблонного кода: необходимо вручную проверять типы, обрабатывать опциональные значения (Optional), писать множество вложенных if let или guard let конструкций. Это делает код громоздким, сложным для чтения и подверженным ошибкам.

SwiftyJSON решает эту проблему, предоставляя элегантный и безопасный API. Вместо того чтобы возиться с сырыми словарями [String: Any] и массивами [Any], вы работаете с объектом JSON, который поддерживает цепочки вызовов (chaining), безопасное извлечение значений с помощью subscript-синтаксиса и автоматическое приведение типов. Библиотека автоматически обрабатывает nil значения, не вызывая крашей приложения, и предоставляет понятные сообщения об ошибках.

Основная задача SwiftyJSON — сделать код, работающий с JSON, таким же чистым и лаконичным, как и сам Swift. Она идеально подходит для проектов, где часто приходится парсить ответы от REST API, обрабатывать конфигурационные файлы или работать с любыми другими JSON-структурами. Библиотека активно поддерживается сообществом, имеет более 22 000 звезд на GitHub и используется в тысячах приложений.

2. Установка

SwiftyJSON распространяется через Swift Package Manager (SPM), CocoaPods и Carthage. Рекомендуемый способ — SPM, так как он встроен в Xcode.

Через Swift Package Manager (рекомендуется)

  1. В Xcode откройте File → Add Packages...
  2. Вставьте URL репозитория: https://github.com/SwiftyJSON/SwiftyJSON.git
  3. Выберите версию (рекомендуется последняя стабильная, например, 5.0.1)
  4. Нажмите Add Package

Или добавьте в Package.swift вашего проекта:

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "YourProject",
    dependencies: [
        .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.1")
    ],
    targets: [
        .target(name: "YourTarget", dependencies: ["SwiftyJSON"])
    ]
)

Через CocoaPods

Добавьте в Podfile:

pod 'SwiftyJSON', '~> 5.0'

Затем выполните pod install.

Через Carthage

Добавьте в Cartfile:

github "SwiftyJSON/SwiftyJSON" ~> 5.0

Затем выполните carthage update.

3. Быстрый старт — минимальный рабочий пример

После установки импортируйте библиотеку и создайте объект JSON из строки или Data:

import SwiftyJSON

// Пример JSON-строки
let jsonString = """
{
    "name": "Alice",
    "age": 30,
    "isStudent": false,
    "address": {
        "city": "New York",
        "zip": "10001"
    },
    "hobbies": ["reading", "swimming", "coding"]
}
"""

// Преобразуем строку в Data
guard let jsonData = jsonString.data(using: .utf8) else {
    fatalError("Не удалось преобразовать строку в Data")
}

// Создаем объект JSON
let json = JSON(jsonData)

// Извлекаем значения
let name = json["name"].stringValue      // "Alice"
let age = json["age"].intValue           // 30
let isStudent = json["isStudent"].boolValue // false
let city = json["address"]["city"].stringValue // "New York"
let firstHobby = json["hobbies"][0].stringValue // "reading"

print("Имя: \(name), Возраст: \(age), Город: \(city)")
print("Первое хобби: \(firstHobby)")

Этот пример показывает ключевую идею: доступ к данным через subscript-синтаксис и использование свойств .stringValue, .intValue, .boolValue для безопасного получения значений с дефолтными значениями.

4. Основные методы/функции/классы

Все операции в SwiftyJSON выполняются через основной класс JSON. Ниже приведены 8 ключевых методов и свойств с подробным описанием.

4.1. Инициализация: JSON(_ data: Data) и JSON(_ string: String)

Сигнатура: init(_ data: Data, options opt: JSONSerialization.ReadingOptions = []) и init(parseJSON jsonString: String)

Что делает: Создает объект JSON из Data или строки. Автоматически парсит данные.

// Из Data
let data = """
{"key": "value"}
""".data(using: .utf8)!
let jsonFromData = JSON(data)

// Из строки
let jsonFromString = JSON(parseJSON: "{\"key\": \"value\"}")
print(jsonFromString["key"].stringValue) // "value"

4.2. .stringValue / .intValue / .boolValue / .doubleValue

Сигнатура: var stringValue: String { get } (аналогично для других типов)

Что делает: Безопасно извлекает значение указанного типа. Если значение отсутствует или имеет другой тип, возвращает "пустое" значение по умолчанию (пустая строка, 0, false, 0.0). Это предотвращает краши приложения.

let json = JSON(parseJSON: "{\"a\": \"hello\", \"b\": 42, \"c\": true}")

print(json["a"].stringValue) // "hello"
print(json["b"].intValue)    // 42
print(json["c"].boolValue)   // true
print(json["d"].stringValue) // "" (пустая строка, так как ключа нет)

4.3. .string / .int / .bool / .double (опциональные)

Сигнатура: var string: String? { get } (аналогично для других типов)

Что делает: Возвращает опциональное значение. Если значение отсутствует или имеет неверный тип, возвращает nil. Полезно, когда нужно различать "значение отсутствует" и "пустое значение".

let json = JSON(parseJSON: "{\"a\": \"hello\", \"b\": null}")

if let name = json["a"].string {
    print("Имя: \(name)") // Имя: hello
}

if let missing = json["b"].string {
    print("Это не выполнится, так как b = null")
} else {
    print("b отсутствует или null") // Выполнится это
}

4.4. .arrayValue / .array

Сигнатура: var arrayValue: [JSON] { get } и var array: [JSON]? { get }

Что делает: Извлекает массив. arrayValue возвращает пустой массив, если значение не является массивом. array возвращает nil.

let json = JSON(parseJSON: "{\"items\": [1, 2, 3], \"notArray\": \"hello\"}")

// Безопасное извлечение
let items = json["items"].arrayValue
for item in items {
    print(item.intValue) // 1, 2, 3
}

// Опциональное извлечение
if let arr = json["items"].array {
    print("Массив из \(arr.count) элементов") // Массив из 3 элементов
}

// Если не массив — пустой массив
print(json["notArray"].arrayValue.count) // 0

4.5. .dictionaryValue / .dictionary

Сигнатура: var dictionaryValue: [String: JSON] { get } и var dictionary: [String: JSON]? { get }

Что делает: Извлекает словарь. Аналогично массивам, dictionaryValue возвращает пустой словарь, если значение не является словарем.

let json = JSON(parseJSON: "{\"user\": {\"name\": \"Bob\", \"age\": 25}}")

if let userDict = json["user"].dictionary {
    print(userDict["name"]?.stringValue ?? "") // Bob
    print(userDict["age"]?.intValue ?? 0)      // 25
}

// Или через dictionaryValue
let dict = json["user"].dictionaryValue
print(dict["name"]?.stringValue ?? "") // Bob

4.6. .exists()

Сигнатура: func exists() -> Bool

Что делает: Проверяет, существует ли значение по указанному пути (ключам). Возвращает true, даже если значение равно null.

let json = JSON(parseJSON: "{\"a\": 1, \"b\": null, \"c\": {\"d\": 2}}")

print(json["a"].exists()) // true (значение 1)
print(json["b"].exists()) // true (значение null, но ключ существует)
print(json["c"]["d"].exists()) // true
print(json["z"].exists()) // false (ключа нет)

4.7. .count

Сигнатура: var count: Int { get }

Что делает: Возвращает количество элементов в массиве или словаре. Для других типов возвращает 0.

let json = JSON(parseJSON: "{\"arr\": [1,2,3], \"dict\": {\"a\":1}, \"str\": \"hello\"}")

print(json["arr"].count)   // 3
print(json["dict"].count)  // 1
print(json["str"].count)   // 0 (строка — не коллекция)

4.8. .rawValue / .rawData() / .rawString()

Сигнатура: var rawValue: Any { get }, func rawData(_ opt: JSONSerialization.WritingOptions = []) throws -> Data, func rawString(_ opt: JSONSerialization.WritingOptions = []) -> String?

Что делает: Преобразует объект JSON обратно в сырые типы (Any, Data, String). Полезно для сериализации.

let json = JSON(parseJSON: "{\"name\": \"Alice\", \"age\": 30}")

// В Any
let anyValue: Any = json.rawValue
print(anyValue) // ["name": "Alice", "age": 30]

// В Data
if let data = try? json.rawData() {
    print(String(data: data, encoding: .utf8)!) // {"name":"Alice","age":30}
}

// В строку
if let string = json.rawString() {
    print(string) // {"name":"Alice","age":30}
}

5. Реальный практический пример (100-200 строк кода)

Рассмотрим реальный сценарий: приложение для просмотра погоды. Мы получаем JSON от API OpenWeatherMap и парсим его с помощью SwiftyJSON.

import Foundation
import SwiftyJSON

// MARK: - Модели данных
struct Weather {
    let cityName: String
    let temperature: Double
    let feelsLike: Double
    let humidity: Int
    let description: String
    let windSpeed: Double
    let clouds: Int
    
    var temperatureString: String {
        return String(format: "%.1f°C", temperature)
    }
}

// MARK: - Сетевой менеджер
class WeatherService {
    private let apiKey = "YOUR_API_KEY_HERE" // Замените на реальный ключ
    
    func fetchWeather(for city: String, completion: @escaping (Result<Weather, Error>) -> Void) {
        let urlString = "https://api.openweathermap.org/data/2.5/weather?q=\(city)&appid=\(apiKey)&units=metric"
        
        guard let url = URL(string: urlString) else {
            completion(.failure(NetworkError.invalidURL))
            return
        }
        
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                completion(.failure(error))
                return
            }
            
            guard let data = data else {
                completion(.failure(NetworkError.noData))
                return
            }
            
            // Парсим JSON с помощью SwiftyJSON
            do {
                let json = try JSON(data: data)
                let weather = self.parseWeather(from: json)
                completion(.success(weather))
            } catch {
                completion(.failure(error))
            }
        }.resume()
    }
    
    private func parseWeather(from json: JSON) -> Weather {
        // Безопасное извлечение всех полей
        let cityName = json["name"].stringValue
        let temperature = json["main"]["temp"].doubleValue
        let feelsLike = json["main"]["feels_like"].doubleValue
        let humidity = json["main"]["humidity"].intValue
        let description = json["weather"][0]["description"].stringValue
        let windSpeed = json["wind"]["speed"].doubleValue
        let clouds = json["clouds"]["all"].intValue
        
        return Weather(
            cityName: cityName,
            temperature: temperature,
            feelsLike: feelsLike,
            humidity: humidity,
            description: description,
            windSpeed: windSpeed,
            clouds: clouds
        )
    }
    
    enum NetworkError: Error {
        case invalidURL
        case noData
    }
}

// MARK: - Использование
let weatherService = WeatherService()
weatherService.fetchWeather(for: "London") { result in                    

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