Как преобразовать строку JSON в словарь (Dictionary) в Swift?
Правильное преобразование JSON строки в словарь
Ваш код почти правильный, но есть одна важная деталь: метод jsonObject(with:options:) возвращает Any, потому что JSON может быть не только словарём, но и массивом. Вам нужно явно привести результат к нужному типу. Вот исправленный вариант:
import Foundation
let jsonString = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"
if let jsonData = jsonString.data(using: .utf8) {
do {
if let dict = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
print(dict) // ["name": "John", "age": 30, "city": "New York"]
// Теперь можно обращаться по ключам
if let name = dict["name"] as? String {
print("Имя: \(name)") // Имя: John
}
if let age = dict["age"] as? Int {
print("Возраст: \(age)") // Возраст: 30
}
} else {
print("Не удалось преобразовать JSON в словарь")
}
} catch {
print("Ошибка парсинга JSON: \(error.localizedDescription)")
}
}
Почему это работает?
Ключевой момент — использование as? [String: Any]. Это опциональное приведение (optional cast). Если JSON действительно является словарём с ключами-строками, вы получите [String: Any]. Если нет (например, если JSON — это массив), то условие if let не сработает, и вы сможете обработать этот случай отдельно.
Что делать с вложенными JSON?
Если ваш JSON содержит вложенные объекты, они тоже будут иметь тип Any. Вам нужно последовательно приводить их к нужным типам:
let nestedJson = """
{
"user": {
"name": "Alice",
"age": 25
},
"hobbies": ["reading", "swimming"]
}
"""
if let data = nestedJson.data(using: .utf8),
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
// Достаём вложенный словарь
if let user = dict["user"] as? [String: Any] {
print(user["name"] as? String ?? "") // Alice
}
// Достаём массив
if let hobbies = dict["hobbies"] as? [String] {
print(hobbies) // ["reading", "swimming"]
}
}
Альтернативный подход с Decodable (рекомендуется для сложных структур)
Для продакшн-кода лучше использовать протокол Codable. Это безопаснее и читаемее:
struct User: Codable {
let name: String
let age: Int
let city: String
}
let jsonString = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"
if let data = jsonString.data(using: .utf8) {
do {
let user = try JSONDecoder().decode(User.self, from: data)
print(user.name) // John
print(user.age) // 30
} catch {
print("Ошибка декодирования: \(error)")
}
}
Важные моменты
- Всегда проверяйте, что строка JSON корректна (используйте
do-catch) - Не забывайте про опциональное приведение типов —
as? [String: Any] - Для сложных структур данных используйте
Codableвместо ручного парсинга - Помните, что
JSONSerializationработает синхронно — для больших данных лучше выносить в фоновый поток
Использование JSONSerialization с опцией .mutableContainers
Если вам нужно изменять полученный словарь (например, добавлять новые ключи), можно использовать опцию .mutableContainers. Она создаёт изменяемые версии словарей и массивов:
let jsonString = "{\"name\":\"John\",\"age\":30}"
if let data = jsonString.data(using: .utf8) {
do {
if var dict = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
dict["country"] = "USA" // Теперь можно изменять словарь
print(dict) // ["name": "John", "age": 30, "country": "USA"]
}
} catch {
print(error)
}
}
Обратите внимание: .mutableContainers возвращает NSMutableDictionary и NSMutableArray, которые мостятся (bridge) к стандартным типам Swift. Это удобно, если нужно модифицировать данные после парсинга, но для большинства задач лучше использовать Codable — он безопаснее по типам и не требует постоянных приведений.
Также полезно знать, что если ваш JSON — это массив (начинается с [), то приведение нужно делать к [[String: Any]]:
let arrayJson = "[{\"id\":1},{\"id\":2}]"
if let data = arrayJson.data(using: .utf8),
let array = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] {
print(array.count) // 2
}
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Docker и Kotlin: контейнеризация приложений для разработчиков