2017-11-10 3 views
1
{ 
"values":[ 
[1,1,7,"Azuan Child","Anak Azuan","12345","ACTIVE","Morning",7,12,"2017-11-09 19:45:00"], 
[28,1,0,"Azuan Child2","Amran","123456","ACTIVE","Evening",1,29,"2017-11-09 19:45:00"] 
] 
} 

[OK]を、これは私がスウィフト4 JSON復号可能な

は、今私は私の構造体にそれを解読したいが、まだそれには運を持っていないサーバーから受信した私のJSON形式です。

struct ChildrenTable: Decodable { 
    var values: [[String]]? 
} 

そしてURLSessionに私の呼び出し元メソッドは、この

URLSession.shared.dataTask(with: request) { (data, response, err) in 
     guard let data = data else { return } 

     let dataAsString = String(data: data, encoding: .utf8) 
     print(dataAsString) 

     do { 
      let children = try 
       JSONDecoder().decode(ChildrenTable.self, from: data) 
       print (children) 
     } catch let jsonErr { 
      print ("Error serializing json: ", jsonErr) 
     } 
    }.resume() 

のように見えると私が得たエラーは、私はint型の配列であります知っていると私は唯一の文字列をキャスト

Error serializing json: 
typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [Vito_Parent.ChildrenTable.(CodingKeys in _1B826CD7D9609504747BED0EC0B7D3B5).values, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0)), 
Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0))], 
debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)) 

です値var values: [[String]]?(なぜこのエラーポップアップの理由)が、私は単純に任意の多次元配列またはタプルを自分の構造体で使用することはできませんので、Decodableのプロトコルに従います。

それはエラーがスローされますので、私はまた、任意のアイデアは、この問題を解決するには、辞書に「辞書を復号化するために期待されたが見つから配列の代わりに」

データを変換することはできませんか?私はデータに文字列型をキャストしようとしましたが、まだ運がありませんでした...

p/s:json形式はすべて文字列型であれば問題ありませんが、それはAPIからです

答えて

1

あなたのjson配列はマルチタイプですが、すべてをデコードしてStringにしようとしています。 StringからDecodableへのデフォルト適合はそれを可能にしません。唯一の解決策は、新しいタイプを導入することです。

struct IntegerOrString: Decodable { 
    var value: Any 

    init(from decoder: Decoder) throws { 
     if let int = try? Int(from: decoder) { 
      value = int 
      return 
     } 

     value = try String(from: decoder) 
    } 
} 

struct ChildrenTable: Decodable { 
    var values: [[IntegerOrString]]? 
} 

Run online

+0

おかげで、非常に巧妙のために使用することができますので、私は少し変更したが、これは複数を扱うときに実行するためのベストプラクティスですJSONDecoderに使用するjsonの配列を入力しますか? –

+0

私はマルチタイプの配列で遭遇するのは初めてです。正直言って、私はjsonが無効だと思った。個人的には、マルチ型配列の配列を送る代わりに、私はバックエンドからオブジェクトの配列を送ります。 –

+0

構造体よりも列挙型を使うほうが良いかもしれません。 – JeremyP

1

JSONで内側の配列は、種類のパターン化配列を有し、そして我々はそのシーケンスが何であるかを知っていることを確認します。内側の配列の型は、3イント、5ストリング、2イント、およびおそらく日付として意図されたものであるパターン付きシーケンスにあります。明らかに、JSONデザイナーの心には、これらの11要素のそれぞれが固定された既知の意味を持っています。

これは、dumpster-divingと手動でJSON式全体をデコードすることで、手動で11個の要素を手動でピックアップできることを意味します。

配列には型が混在していますが、Swiftではそれが嫌いです。したがって、それらをAny(またはAnyObject)の配列として表現する必要があります。 は、自身としてとして入手することができます。人工の中間構造体にラップする必要はありません。

ところで、各要素の意味を知っていれば、Any配列の代わりに内部配列を構造化して各要素の意味を表す11個の名前付きプロパティを持つ構造体にデコードできます。それはよりクリーンな結果になりますが、私は11値の意味を知らないので使用していません。

ここで行く:

struct S : Decodable { 
    var values : [[Any]] 
    enum CodingKeys : String, CodingKey { 
     case values 
    } 
    init(from decoder: Decoder) throws { 
     // get the dictionary 
     let con = try! decoder.container(keyedBy: CodingKeys.self) 
     // get the "values" array of array 
     var con2 = try! con.nestedUnkeyedContainer(forKey: CodingKeys.values) 
     var bigarr = [[Any]]() 
     for _ in 0..<con2.count! { 
      // get a nested array 
      var con3 = try! con2.nestedUnkeyedContainer() 
      // decode all the elements of the nested array 
      var arr = [Any]() 
      arr.append(try! con3.decode(Int.self)) 
      arr.append(try! con3.decode(Int.self)) 
      arr.append(try! con3.decode(Int.self)) 
      arr.append(try! con3.decode(String.self)) 
      arr.append(try! con3.decode(String.self)) 
      arr.append(try! con3.decode(String.self)) 
      arr.append(try! con3.decode(String.self)) 
      arr.append(try! con3.decode(String.self)) 
      arr.append(try! con3.decode(Int.self)) 
      arr.append(try! con3.decode(Int.self)) 
      arr.append(try! con3.decode(String.self)) 
      bigarr.append(arr) 
     } 
     // all done! finish initialization 
     self.values = bigarr 
    } 
} 

let result = try! JSONDecoder().decode(S.self, from: jdata) 
print(result.values) 
// [[1, 1, 7, "Azuan Child", "Anak Azuan", "12345", "ACTIVE", 
// "Morning", 7, 12, "2017-11-09 19:45:00"], 
// [28, 1, 0, "Azuan Child2", "Amran", "123456", "ACTIVE", 
// "Evening", 1, 29, "2017-11-09 19:45:00"]] 
+0

素敵なので、配列の型と要素数を知っているときにのみ使用できます。 –

+0

修正!しかし、私たちはそれを知っています。このJSONは明らかに_type_と_meaning_をそれぞれの配列要素に与えます。それが何であるかを知っていれば、内側の配列を_struct_に解析することができます。 – matt

+0

ええ、これについて質問してくれてありがとう。私が言ったように、私はこれを試してみたいと思っています。 – matt

0

私は私のプロジェクトで、ソリューション、および魔法のようにその作品を使用しようとしました。以下は、それは一つの文字列、単一のアレイ、および多次元配列

struct TripModel: Decodable { 
var tx_result: Any 
var columns: [Any] 
var values: [[Any]] 

enum CodingKeys : String, CodingKey { 
    case tx_result 
    case columns 
    case values 
} 

init(from decoder: Decoder) throws { 
    var bigarr = [[Any]]() 
    var arrColumn = [Any]() 
    // get the dictionary 
    let con = try! decoder.container(keyedBy: CodingKeys.self) 

    let conResult = try! con.decode(String.self, forKey: CodingKeys.tx_result) 

    var conColumns = try! con.nestedUnkeyedContainer(forKey: CodingKeys.columns) 
    //print(String(describing: conColumns.count)) 

    // get the "values" array of array 
    var con2 = try! con.nestedUnkeyedContainer(forKey: CodingKeys.values) 

    for _ in 0..<con2.count! { 
     // get a nested array 
     var con3 = try! con2.nestedUnkeyedContainer() 
     // decode all the elements of the nested array 
     var arr = [Any]() 
     arr.append(try! con3.decode(Int.self)) 
     arr.append(try! con3.decode(Int.self)) 
     arr.append(try! con3.decode(Int.self)) 
     arr.append(try! con3.decode(Int.self)) 
     arr.append(try! con3.decode(String.self)) 
     arr.append(try! con3.decode(String.self)) 
     arr.append(try! con3.decode(String.self)) 
     arr.append(try! con3.decode(Int.self)) 
     arr.append(try! con3.decode(Int.self)) 
     arr.append(try! con3.decode(Double.self)) 
     arr.append(try! con3.decode(String.self)) 
     bigarr.append(arr) 
    } 

     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 
     arrColumn.append(try! conColumns.decode(String.self)) 

    // all done! finish initialization 
    self.tx_result = conResult 
    self.columns = arrColumn 
    self.values = bigarr 
} 

}

関連する問題