У меня есть некоторый JSON, который содержит другой объект JSON внутри в виде строки (обратите внимание на кавычки вокруг значения "jsonString"):
{
"jsonString":"{\"someKey\": \"Some value\"}"
}
Я знаю, что если бы значение "jsonString" не заключалось в кавычки, я бы сделал что-то вроде этого:
import Foundation
struct Something: Decodable {
struct SomethingElse: Decodable {
let someKey: String
}
let jsonString: SomethingElse
}
let jsonData = """
{
"jsonString":"{\"someKey\": \"Some value\"}"
}
""".data(using: .utf8)!
let something = try! JSONDecoder().decode(Something.self, from: jsonData)
Но это не работает для моего случая. Это не сработает, даже если я буду рассматривать "jsonString" как String и делать что-то вроде этого:
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: SomethingKey.self)
let jsonStringString = try container.decode(String.self, forKey: .jsonString)
if let jsonStringData = jsonStringString.data(using: .utf8) {
self.jsonString = try JSONDecoder().decode(SomethingElse.self, from: jsonStringData)
} else {
self.jsonString = SomethingElse(someKey: "")
}
}
private enum SomethingKey: String, CodingKey {
case jsonString
}
Ошибка, которую я испытываю:
Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Badly formed object around line 2, column 18." UserInfo = {NSDebugDescription=Badly formed object around line 2, column 18., NSJSONSerializationErrorIndex=20})))
Однако все валидаторы JSON, которые я пробовал, говорят, что JSON действителен и соответствует RFC 8259.
Swift также не позволяет мне избежать вложенных "{" и "}".
К сожалению, формат JSON находится вне моего контроля, и я не могу его изменить.
Я также нашел вопрос это, который выглядит похожим, но там ничего не работает. Ответы актуальны только для обычных вложенных объектов JSON. Или я что-то пропустил.
Любая помощь приветствуется!
JSON должен быть {"jsonString": "{\"someKey\": \"someValue\"}"}, исключая двойные кавычки внутри значения jsonString. Указанный недействителен. В своем пользовательском init(from decoder:) не могли бы вы напечатать let jsonString?
Ошибка говорит о том, что JSON вообще недействителен, а не часть try container.decode(String.self, forKey: .jsonString), JSON Stringified с JSON.
@phuzi Я обновил вопрос, немного переформатировал и дополнил некоторыми деталями. JSON действителен.
@Larme Я обновил вопрос, немного переформатировал и дополнил некоторыми деталями. JSON действителен. init(from decoder: Decoder) даже не вызывается, ошибка вылетает на строку JSONDecoder().decode(Something.self, from: jsonData). Пожалуйста, попробуйте вставить мой фрагмент кода в Playground, и вы сразу поймете, что я имею в виду.
Это потому, что в jsonData, которое вы дали, оно плохо создано. это либо: let jsonData = """--{"jsonString":"{\\"someKey\\": \\"Some value\\"}"}---""".data(using: .utf8)!, где "--" — это новая строка в среде IDE, либо let jsonData = #"{"jsonString":"{\"someKey\": \"Some value\"}"}"#.data(using: .utf8)!, поскольку при объявлении строки вам все равно нужно экранировать обратную косую черту.
@Ларме Гений! Оба варианта сработали, как и ожидалось, большое спасибо! Если вы опубликуете свою находку в качестве ответа, я с радостью отмечу ее как принятую. ;)
(Еще одна вещь, о которой стоит упомянуть, это то, что я не знал, что не могу добавлять разрывы строк внутри этой вложенной строки JSON.)

Ошибка говорит о том, что весь JSON недействителен, а не только значение jsonString.
Хотя это правда (вы можете проверить это в онлайн-валидаторе, например, JSONLint):
{
"jsonString": "{\"someKey\": \"Some value\"}"
}
При объявлении его как строки в Swift вам нужно убедиться, что обратная косая черта действительно присутствует.
Так что это:
let jsonString = """
{ "jsonString": "{\\"someKey\\": \\"Some value\\"}"}
"""
или
let jsonString = #"{"jsonString":"{\"someKey\": \"Some value\"}"}"#
На мой взгляд, это не похоже на действительный JSON!