2017-11-02 18 views
2

ここに新しいとスウィフトので、私に簡単に行ってください。スウィフト4のJSON解析ヘルプ - データ構造の問題?

入れ子になった辞書を含むJSONを解析しようとするとちょっとスタックされています。私は、私が作成したデータストラテジで何かが間違っていると想像しています。私は修正するために全力を尽くしましたが、同じ問題がまだ発生しています。

これは、私が一緒に仕事しようとしていますJSON APIです: https://api.coindesk.com/v1/bpi/currentprice.json

これらは私がこのモデル化するために作成したデータ構造です:

struct base: Decodable { 

    let disclaimer: String 
    let bpi: [Bpi] 
} 

struct Bpi: Decodable { 
    let USD: [USD] 
} 

struct USD: Decodable { 
    let rate_float: Float 
} 

そして、ここでは、VCでの私のコードです:

override func viewDidLoad() { 
    super.viewDidLoad() 

    let jsonURLString = "https://api.coindesk.com/v1/bpi/currentprice.json" 

    guard let url = URL(string: jsonURLString) else {return} 

    URLSession.shared.dataTask(with: url) { (data, response, err) in 

     guard let data = data else {return} 

     do { 
      let bitcoinData = try JSONDecoder().decode(base.self, from: data) 
      print(bitcoinData.bpi) 
     } catch { 
      print("error") 
     } 

    } .resume() // Fires off the session 
} 

免責事項の文字列またはルート辞書の他の文字列からデータを取得できますが、そのとおりです。入れ子にされた双子座では何も解析することができません。ただキャッチエラーを返すだけです。ここで

はJSONです:

{ 
    "time": { 
     "updated": "Nov 2, 2017 06:08:00 UTC", 
     "updatedISO": "2017-11-02T06:08:00+00:00", 
     "updateduk": "Nov 2, 2017 at 06:08 GMT" 
    }, 
    "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org", 
    "chartName": "Bitcoin", 
    "bpi": { 
     "USD": { 
      "code": "USD", 
      "symbol": "$", 
      "rate": "6,889.4013", 
      "description": "United States Dollar", 
      "rate_float": 6889.4013 
     }, 
     "GBP": { 
      "code": "GBP", 
      "symbol": "£", 
      "rate": "5,184.4053", 
      "description": "British Pound Sterling", 
      "rate_float": 5184.4053 
     }, 
     "EUR": { 
      "code": "EUR", 
      "symbol": "€", 
      "rate": "5,910.4587", 
      "description": "Euro", 
      "rate_float": 5910.4587 
     } 
    } 
} 

は、私ははっきりとここに間違ってやっている何かがありますか?

事前にお手数をおかけしていただきありがとうございます。私の書式設定がうまくいけばごめんなさい! - それは動作しますこれでモデル次

+0

https://danieltmbr.github.io/JsonCodeGenerator/

をそれは次のような出力を生成します/ SwiftyJSON)。それらはあなたのための*ロット*簡単になります。 – LinusGeffarth

+0

@LinusGeffarth SwifftyJSONは、JSON( 'Codable'プロトコルと' JSONEncoder'/'JSONDecoder')を扱うためのアップル独自の実装よりも優れていますか? –

+0

私はSwiftyJSONを使ってJSON(data:Data)を入れてからループを介してアクセスし、 'json [キー "]。私はそれを簡単に見つける@ØyvindHauge – LinusGeffarth

答えて

1

てみてください、bpiUSDの両方が、1つだけの値の配列ではありません:両方のジェネリック型KVが復号化可能である場合に

struct base: Decodable { 

    let disclaimer: String 
    let bpi: Bpi 
} 

struct Bpi: Decodable { 
    let USD: USD 
} 

struct USD: Decodable { 
    let rate_float: Float 
} 
0

辞書(Dictionary<K,V>)は、暗黙的にDecodable準拠しています。

struct Coin: Decodable { 

    private enum CodingKeys : String, CodingKey { 
     case code, symbol, rate, description, rateFloat = "rate_float" 
    } 

    let code : String 
    let symbol : String 
    let rate : String 
    let description : String 
    let rateFloat : Float 
} 

あなたが簡単に任意のコードを追加することなく、[String:Coin]として

struct Base: Decodable { 

    private enum CodingKeys : String, CodingKey { 
     case disclaimer, coins = "bpi" 
    } 

    let disclaimer: String 
    let coins: [String:Coin] 
} 

を通貨辞書をデコードし、使用することができますが、通貨のための構造体​​を作成すると仮定すると、それ

let bitcoinData = try JSONDecoder().decode(Base.self, from: data) 
print(bitcoinData.coins) 

​​のように通貨を設定する場合は、カスタムイニシャライザを作成し、辞書値を配列にマップすることができます。

この例では、time辞書

struct Base: Decodable { 

    struct Time : Decodable { 

     private enum CodingKeys : String, CodingKey { 
      case updated = "updatedISO" 
     } 

     let updated : Date 
    } 

    private enum CodingKeys : String, CodingKey { 
     case disclaimer, bpi, time 
    } 

    let disclaimer: String 
    let coins: [Coin] 
    let updated : Date 

    init(from decoder: Decoder) throws { 
     let container = try decoder.container(keyedBy: CodingKeys.self) 
     disclaimer = try container.decode(String.self, forKey: .disclaimer) 
     let bpi = try container.decode([String:Coin].self, forKey: .bpi) 
     coins = Array(bpi.values.sorted(by: {$0.code < $1.code})) 
     let time = try container.decode(Time.self, forKey: .time) 
     updated = time.updated 
    } 
} 

そして

let decoder = JSONDecoder() 
decoder.dateDecodingStrategy = .iso8601 
let bitcoinData = try decoder.decode(Base.self, from: data) 
print(bitcoinData.coins) 
0

この例を使用してもupdatedISO値をデコードあなたは配列としてあなたのBPI &使用特性を宣言したが、彼らは辞書(ネストされたJSONオブジェクトでした)。あなたがサンプルJSONを持っている場合は、このコンバータ次回試すことができます:私は[SwiftyJSON](https://github.com/SwiftyJSONのようなライブラリを使用してお勧めします

struct Root: Codable { 

    let time: Time 
    let disclaimer: String 
    let chartName: String 
    let bpi: Bpi 

} 

struct Time: Codable { 

    let updated: String 
    let updatedISO: String 
    let updateduk: String 

} 

struct Bpi: Codable { 

    let USD: USD 
    let GBP: USD 
    let EUR: USD 

} 

struct USD: Codable { 

    let code: String 
    let symbol: String 
    let rate: String 
    let description: String 
    let rateFloat: Double 

    private enum CodingKeys: String, CodingKey { 
    case code 
    case symbol 
    case rate 
    case description 
    case rateFloat = "rate_float" 
    } 
}