私はこのようなバックエンドからの応答文字列を持っています:
{
"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")
}
まず、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)
}
これは答え@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
}
}
"" "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)
}
}
}