Сериализация строки JSON, которая содержит экранированные (обратная косая черта и двойная кавычка) Swift return Плохо сформированный объект - PullRequest
0 голосов
/ 16 мая 2018

У меня есть строка ответа от бэкэнда, например:

{
    "status": "success",
    "data": "{\"name\":\"asd\",\"address\":\"Street 1st\"}"
}

Я думаю, что проблема была в том, что двойная кавычка (") в строке данных. Когда я удалял двойную кавычку, сериализация прошла успешноНо ответ от бэкэнда, и я должен разобраться с ним.

Кто-нибудь может решить эту проблему?

Спасибо.

Вот код игровой площадки.

import Foundation
var jsonStr = """
{
"status": "success",
"data": "{\"name\":\"asd\",\"address\":\"Street 1st\"}"
}
"""
let data = jsonStr.data(using: .utf8)
if let d = data {
    do {
        let o = try JSONSerialization.jsonObject(with: d)
        print(o)
    } catch let e {
        print(e)
    }
} else {
    print("DATA conversion ERROR")
}

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

В вашем коде есть ошибка, так как вы пишете его в таком коде "" "json" "",

также data это String не словарь, поэтому вам нужно будет преобразоватьзатем к данным JSONSerialization снова

проверяю код я добавляю ваш ответ в файл Json и анализирую его, и работаю правильно

Так что просто запишите это в файл json под названием data.json

{
    "status": "success",
    "data": "{\"name\":\"asd\",\"address\":\"Street 1st\"}"
}

и используйте это:

            guard let  jsonFile =  Bundle.main.path(forResource: "data", ofType: "json") else { return}

            guard  let data = try? Data(contentsOf: URL(fileURLWithPath: jsonFile), options: .mappedIfSafe) else {return}

            if let response  = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) {
                print(response)
                if let dataInDictionary = response as? [String:Any] , let addresData = dataInDictionary["data"] as? String {

                    if let jsonData = addresData.data(using: .utf8),
                        let dictionary = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves) as? [String:Any]{
                        print(dictionary)
                    }
                }
            }
0 голосов
/ 01 мая 2019

Вот еще один пример, основанный на ответе @vadian

Swift 4 - Использование Codable

Это был JSON, который я получил:

{
    "error_code": 0,
    "result": {
        "responseData": "{\"emeter\":{\"get_realtime\":{\"voltage_mv\":237846,\"current_ma\":81,\"power_mw\":7428,\"total_wh\":1920,\"err_code\":0}}}"
    }
} 

Часть JSON с обратной косой чертой равна этому:

{
    "emeter": {
        "get_realtime": {
            "voltage_mv": 237846,
            "current_ma": 81,
            "power_mw": 7428,
            "total_wh":19201,
            "err_code":0
        }
    }
}

И этот код я использовал:

import Foundation

class RealtimeEnergy: Codable {
    let errorCode: Int
    let result: ResultRealtimeEnergy?
    let msg: String?

    enum CodingKeys: String, CodingKey {
        case errorCode = "error_code"
        case result, msg
    }

    init(errorCode: Int, result: ResultRealtimeEnergy?, msg: String?) {
        self.errorCode = errorCode
        self.result = result
        self.msg = msg
    }
}

class ResultRealtimeEnergy: Codable {

    let responseData: String
    var emeter: Emeter

    enum CodingKeys: String, CodingKey {
        case responseData
    }

    required init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        responseData = try container.decode(String.self, forKey: .responseData)
        let dataString = try container.decode(String.self, forKey: .responseData)
        emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))
    }
}



class Emeter: Codable {
    let emeter: EmeterClass

    init(emeter: EmeterClass) {
        self.emeter = emeter
    }
}

class EmeterClass: Codable {
    let getRealtime: GetRealtime

    enum CodingKeys: String, CodingKey {
        case getRealtime = "get_realtime"
    }

    init(getRealtime: GetRealtime) {
        self.getRealtime = getRealtime
    }
}

class GetRealtime: Codable {
    let voltageMv, currentMa, powerMw, totalWh: Int
    let errCode: Int

    enum CodingKeys: String, CodingKey {
        case voltageMv = "voltage_mv"
        case currentMa = "current_ma"
        case powerMw = "power_mw"
        case totalWh = "total_wh"
        case errCode = "err_code"
    }

    init(voltageMv: Int, currentMa: Int, powerMw: Int, totalWh: Int, errCode: Int) {
        self.voltageMv = voltageMv
        self.currentMa = currentMa
        self.powerMw = powerMw
        self.totalWh = totalWh
        self.errCode = errCode
    }
}
0 голосов
/ 16 мая 2018

Прежде всего, если вы заключите JSON в синтаксис литеральной строки Swift 4, вы должны избежать обратной косой черты.

let jsonStr = """
{
"status": "success",
"data": "{\\"name\\":\\"asd\\",\\"address\\":\\"Street 1st\\"}"
}
"""

Вы получили вложенный JSON.Значение для ключа data - это другая строка JSON, которую необходимо десериализовать отдельно

let jsonData = Data(jsonStr.utf8)

do {
    if let object = try JSONSerialization.jsonObject(with: jsonData) as? [String:String] {
        print(object)
        if let dataString = object["data"] as? String {
            let dataStringData = Data(dataString.utf8)
            let dataObject = try JSONSerialization.jsonObject(with: dataStringData) as? [String:String]
            print(dataObject)
        }
    }
} catch {
    print(error)
}

Или - с чуть большими затратами, но - намного удобнее с протоколом (De)Codable

struct Response : Decodable {

    private enum CodingKeys : String, CodingKey { case status, data }

    let status : String
    let person : Person

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decode(String.self, forKey: .status)
        let dataString = try container.decode(String.self, forKey: .data)
        person = try JSONDecoder().decode(Person.self, from: Data(dataString.utf8))
    }
}

struct Person : Decodable {
    let name, address : String
}

let jsonStr = """
{
"status": "success",
"data": "{\\"name\\":\\"asd\\",\\"address\\":\\"Street 1st\\"}"
}
"""
let jsonData = Data(jsonStr.utf8)

do {
    let result = try JSONDecoder().decode(Response.self, from: jsonData)
    print(result)
} catch {
    print(error)
}
...