Swift 4 decodable и новые строки \ n

API поиска iTunes возвращает JSON, который иногда содержит символы новой строки (\ n).

Это приводит к сбою декодирования.

Вы можете увидеть пример здесь:

локон "https://itunes.apple.com/search?term=Ruismaker&entity=software&media=software&limit=1"

Вот моя урезанная (в фактическом ответе) структура домена:

public struct iTunesSoftware: Codable {

    enum CodingKeys: String, CodingKey {
        case iTunesDescription = "description"
    }

    public var iTunesDescription: String?
}

Вот тестовый код:

let jstring = """
{
"description": "This App requires \n iPad 4, Mini 2",
}
"""
// try it with and without the newline to see the problem
let encoded = String(jstring.filter { !" \n\t\r".contains($0) })
let encodedData = encoded.data(using: .utf8)!
//let encodedData = jstring.data(using: .utf8)!

А затем расшифруйте:

let decoder = JSONDecoder()    
do {
        let app = try decoder.decode(iTunesSoftware.self, from: encodedData)
        print(app)
    } catch {
        print(error)
    }

Но на практике вы получаете объект Data из вызова службы REST.

 let task = session.dataTask(with: url) {
                (data, _, err) -> Void in

                 // I have a Data object, not a String here.
                 // I can do this:
                 if let s = String(data: data, encoding: .utf8) {
                      filter it, turn it back into a Data object, then decode
                      let encoded = String(s.filter { !" \n\t\r".contains($0) })
                      let encodedData = encoded.data(using: .utf8)
                      var encodedData: Data?
                      if let s = String(data: responseData, encoding: .utf8) {
                          // filter it, turn it back into a Data object, then decode
                          let encoded = String(s.filter { !" \n\t\r".contains($0) })
                          encodedData = encoded.data(using: .utf8)
                      }
                      guard let theData = encodedData else {
                         return
                      }

                      // and then later:
                      let app = try decoder.decode(iTunesSoftware.self, from: theData)

Итак, мой вопрос: правда? Это очень распространенный вариант использования - и он исходит от службы Apple REST. Можно подумать, что декодер позволит вам установить что-то, чтобы игнорировать управляющие символы.

JSONDecoder имеет различные свойства стратегии, например:

open var dataDecodingStrategy: JSONDecoder.DataDecodingStrategy

Вы должны создать собственный KeyedDecodingContainer, чтобы переопределить декодирование для String?

Я упускаю что-то очевидное?

На самом деле JSONDecoder должен правильно декодировать строки, содержащие символы новой строки и пробелы. Обратный слэш в буквальной строке примера должен быть экранирован "description": "This App requires \\n iPad 4, Mini 2".

vadian 11.04.2018 13:03

Согласно json.org, управляющие символы недопустимы в строках JSON, и символ новой строки должен быть экранирован как \n (который является \\n в строковом литерале Swift). - Можете ли вы поделиться URL-адресом, который возвращает такой проблемный ответ?

Martin R 11.04.2018 13:05

API поиска iTunes возвращает его. Вот пример, где это можно увидеть. Посмотрите описание. локон "itunes.apple.com/…"

Gene De Lisa 11.04.2018 13:16

Я не вижу новой строки внутри строк в этом ответе, только \n (т.е. символ обратной косой черты, за которым следует "n").

Martin R 11.04.2018 13:19

\ N - это то, что заставляет декодер отключаться.

Gene De Lisa 11.04.2018 13:25

@GeneDeLisa: приведенный выше тестовый код создает строку, содержащую символ новой строки (U + 000A). Ответ этого iTunes API содержит нет символы новой строки внутри строк, только последовательности обратной косой черты-n, то есть сбежал символы новой строки. Приведенный выше пример отличается от того, что возвращает iTunes API. - Вставка ответа iTunes в jsonlint.com не сообщает об ошибках. Ваша проблема, должно быть, в другом.

Martin R 11.04.2018 13:28

Какое точное сообщение об ошибке?

Martin R 11.04.2018 13:39
2
7
1 551
1

Ответы 1

Один из уроков, которые я усвоил и усвоил заново за 36 лет программирования, - «это не то, что вы думаете». Я думал, что это странная проблема с декодированием. Итак, я перешел от своего QuickSpec к игровой площадке, чтобы изолировать его. Неплохо, но было 5 утра, и тогда у меня был только один эспрессо.

tl; dr проблема заключалась в моём макете сеанса тестирования, который читал json из файла. Обычно я провожу оба теста - реальные сетевые вызовы и из файла. Я по ошибке скопировал в файл мусор. D'Oh!

Спасибо за ваши ответы. Думаю, твой день начинается лучше, чем мой :)

Другие вопросы по теме