2017-09-21 3 views
0

Ich möchte Swift 4's codable-Funktion mit JSON verwenden, aber einige der Schlüssel haben keinen festgelegten Namen. Eher gibt es ein Array und sie sind IDs wieSwift 4 JSON Codable IDs als Schlüssel

{ 
"status": "ok", 
"messages": { 
    "generalMessages": [], 
    "recordMessages": [] 
}, 
"foundRows": 2515989, 
"data": { 
    "181": { 
    "animalID": "181", 
    "animalName": "Sophie", 
    "animalBreed": "Domestic Short Hair/Domestic Short Hair/Mixed (short coat)", 
    "animalGeneralAge": "Adult", 
    "animalSex": "Female", 
    "animalPrimaryBreed": "Domestic Short Hair", 
    "animalUpdatedDate": "6/26/2015 2:00 PM", 
    "animalOrgID": "12", 
    "animalLocationDistance": "" 

wo Sie die 181 IDs sehen. Kann jemand mit dem 181 umgehen, damit ich es als Schlüssel spezifizieren kann? Die Nummer kann eine beliebige Nummer sein und ist für jede unterschiedlich.

wäre in etwa so

struct messages: Codable { 
    var generalMessages: [String] 
    var recordMessages: [String] 
} 

struct data: Codable { 
    var 
} 

struct Cat: Codable { 
    var Status: String 
    var messages: messages 
    var foundRows: Int 
    //var 181: [data] //What do I place here 
} 

Vielen Dank im Voraus möchten.

+0

Die '181' ist eine Zeichenfolge (umgeben von' '' '). Sie greifen also nicht auf element ["data"] [181] 'sondern auf' element ["data"] ["181"] 'zu (beachten Sie die doppelten Anführungszeichen). Ist es das, wonach du fragst? –

+0

Danke für die Antwort. Ich habe meine Frage aktualisiert, um mich klarer zu machen. –

Antwort

2

Bitte überprüfen Sie:

struct ResponseData: Codable { 
    struct Inner : Codable { 
     var animalID : String 
     var animalName : String 

     private enum CodingKeys : String, CodingKey { 
      case animalID  = "animalID" 
      case animalName = "animalName" 
     } 
    } 

    var Status: String 
    var foundRows: Int 
    var data : [String: Inner] 

    private enum CodingKeys: String, CodingKey { 
     case Status = "status" 
     case foundRows = "foundRows" 
     case data = "data" 
    } 
} 

let json = """ 
    { 
     "status": "ok", 
     "messages": { 
      "generalMessages": ["dsfsdf"], 
      "recordMessages": ["sdfsdf"] 
     }, 
     "foundRows": 2515989, 
     "data": { 
      "181": { 
       "animalID": "181", 
       "animalName": "Sophie" 
      }, 
      "182": { 
       "animalID": "182", 
       "animalName": "Sophie" 
      } 
     } 
    } 
""" 
let data = json.data(using: .utf8)! 
let decoder = JSONDecoder() 

do { 
    let jsonData = try decoder.decode(ResponseData.self, from: data) 
    for (key, value) in jsonData.data { 
     print(key) 
     print(value.animalID) 
     print(value.animalName) 
    } 
} 
catch { 
    print("error:\(error)") 
} 
0

Ich glaube nicht, dass Sie eine Zahl als Variablennamen deklarieren können. Von Apple's doc:

Konstante und Variablennamen enthalten, können nicht Leerzeichen, mathematische Symbole, Pfeile, privaten Gebrauch (oder ungültig) Unicode-Code Punkte oder linien- und Box-Zeichnung Zeichen. Sie können auch nicht mit einer Nummer beginnen, obwohl Nummern an anderer Stelle im Namen enthalten sein können.

Ein richtiger Weg ist eine Eigenschaft, die Ihre key erfasst.

struct Cat: Codable { 
    var Status: String 
    var messages: messages 
    var foundRows: Int 
    var key: Int // your key, e.g., 181 
} 
+0

Sie haben Recht, aber ich versuche herauszufinden, was ich dort platzieren muss. –

+0

Verwenden Sie einfach eine Variable, um Ihren Schlüssel zu speichern – Lawliet

0

Ich würde so etwas wie dies vorschlagen: -

struct ResponseData: Codable { 
struct AnimalData: Codable { 
    var animalId: String 
    var animalName: String 

    private enum CodingKeys: String, CodingKey { 
     case animalId = "animalID" 
     case animalName = "animalName" 
    } 
} 

var status: String 
var foundRows: Int 
var data: [AnimalData] 

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

struct AnimalIdKey: CodingKey { 
    var stringValue: String 
    init?(stringValue: String) { 
     self.stringValue = stringValue 
    } 
    var intValue: Int? { return nil } 
    init?(intValue: Int) { return nil } 
} 

init(from decoder: Decoder) throws { 
    let container = try decoder.container(keyedBy: CodingKeys.self) 
    let animalsData = try container.nestedContainer(keyedBy: AnimalIdKey.self, forKey: .data) 

    self.foundRows = try container.decode(Int.self, forKey: .foundRows) 
    self.status = try container.decode(String.self, forKey: .status) 
    self.data = [] 
    for key in animalsData.allKeys { 
     print(key) 
     let animalData = try animalsData.decode(AnimalData.self, forKey: key) 
     self.data.append(animalData) 
    } 
    } 
} 

let string = "{\"status\":\"ok\",\"messages\":{\"generalMessages\":[],\"recordMessages\":[]},\"foundRows\":2515989,\"data\":{\"181\":{\"animalID\":\"181\",\"animalName\":\"Sophie\"}}}" 
let jsonData = string.data(using: .utf8)! 
let decoder = JSONDecoder() 
let parsedData = try? decoder.decode(ResponseData.self, from: jsonData) 

Auf diese Weise Ihren Decoder initializer selbst die Schlüssel behandelt.