まず、リモートURLからデータを同期的にロードしないでくださいURLSession
。常に、非同期メソッドを使用してください。
「Any」には添え字メンバーがありません
これは、コンパイラーが中間オブジェクトのタイプを認識していないため(たとえばcurrently
、["currently"]!["temperature"]
)NSDictionary
、コンパイラーのようにFoundationコレクションタイプを使用しているため、タイプについてまったく認識していません。
さらに、Swift 3では、すべての添え字付きオブジェクトのタイプについてコンパイラーに通知する必要があります。
JSONシリアル化の結果を実際の型にキャストする必要があります。
このコードはURLSession
、Swiftネイティブ型のみを使用します
let urlString = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let currentConditions = parsedData["currently"] as! [String:Any]
print(currentConditions)
let currentTemperatureF = currentConditions["temperature"] as! Double
print(currentTemperatureF)
} catch let error as NSError {
print(error)
}
}
}.resume()
currentConditions
あなたが書くことができるすべてのキー/値のペアを印刷するには
let currentConditions = parsedData["currently"] as! [String:Any]
for (key, value) in currentConditions {
print("\(key) - \(value) ")
}
に関するメモjsonObject(with data
:
多くの(すべてのように思われる)チュートリアルが提案する.mutableContainers
か.mutableLeaves
、Swiftではまったくナンセンスなオプションです。2つのオプションは、結果をNSMutable...
オブジェクトに割り当てるための従来のObjective-Cオプションです。Swiftでは、すべてのvar
iableはデフォルトで変更可能であり、これらのオプションのいずれかを渡して結果をlet
定数に割り当ててもまったく効果がありません。さらに、ほとんどの実装では、逆シリアル化されたJSONを変更することはありません。
スイフトに有用であるのみ(まれな)オプションがある.allowFragments
JSONルートオブジェクトは値型とすることができる場合ならば必要とされる(String
、Number
、Bool
またはnull
)ではなくコレクション・タイプのいずれか(array
またはdictionary
)。ただし、通常は、オプションなしoptions
を意味するパラメーターを省略します。
================================================== =========================
JSONを解析するための一般的な考慮事項
JSONは適切に配置されたテキスト形式です。JSON文字列を読み取るのは非常に簡単です。文字列を注意深く読んでください。型は6つしかありません。2つのコレクション型と4つの値型です。
コレクションの種類は
- 配列 -JSON:大括弧内のオブジェクト
[]
-Swift:[Any]
ほとんどの場合[[String:Any]]
- 辞書 -JSON:中括弧内のオブジェクト
{}
-Swift:[String:Any]
値のタイプは
- 文字列 -JSON:二重引用符
"Foo"
で囲まれた任意の値、"123"
または"false"
- またはSwift:String
- 番号 - JSON:数値ではない二重引用符で
123
か123.0
-スウィフト:Int
またはDouble
- ブール - JSON:
true
かfalse
いない二重引用符で-スウィフト:true
またはfalse
- null -JSON:
null
– Swift:NSNull
JSON仕様によれば、辞書のすべてのキーはである必要がありますString
。
基本的には、オプションのバインディングを使用してオプションを安全にアンラップすることを常にお勧めします
ルートオブジェクトが辞書({}
)の場合、型を[String:Any]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...
キーで値を取得します(OneOfSupportedJSONTypes
上記のように、JSONコレクションまたは値のタイプです)。
if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {
print(foo)
}
ルートオブジェクトが配列([]
)の場合、型を[[String:Any]]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...
と配列を繰り返します
for item in parsedData {
print(item)
}
特定のインデックスのアイテムが必要な場合は、インデックスが存在するかどうかも確認してください
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
let item = parsedData[2] as? OneOfSupportedJSONTypes {
print(item)
}
}
JSONがコレクションタイプではなく、単に値タイプの1つであるまれなケースでは、.allowFragments
オプションを渡して、結果を適切な値タイプにキャストする必要があります。
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...
AppleはSwiftブログで包括的な記事を公開しています:Swift でのJSONの操作
================================================== =========================
Swift 4以降では、Codable
プロトコルはJSONを直接構造体/クラスに解析するより便利な方法を提供します。
たとえば、質問で指定されたJSONサンプル(わずかに変更)
let jsonString = """
{"icon": "partly-cloudy-night", "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precip_intensity": 0, "wind_speed": 6.04, "summary": "Partly Cloudy", "ozone": 321.13, "temperature": 49.45, "dew_point": 41.75, "apparent_temperature": 47, "wind_bearing": 332, "cloud_cover": 0.28, "time": 1480846460}
"""
構造体にデコードできますWeather
。Swiftタイプは上記と同じです。追加のオプションがいくつかあります。
- を表す文字列は、
URL
として直接デコードできますURL
。
time
整数として復号することができるDate
とdateDecodingStrategy
.secondsSince1970
。
- snaked_cased JSONキーをキャメルケースに変換するには、
keyDecodingStrategy
.convertFromSnakeCase
struct Weather: Decodable {
let icon, summary: String
let pressure: Double, humidity, windSpeed : Double
let ozone, temperature, dewPoint, cloudCover: Double
let precipProbability, precipIntensity, apparentTemperature, windBearing : Int
let time: Date
}
let data = Data(jsonString.utf8)
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(Weather.self, from: data)
print(result)
} catch {
print(error)
}
その他のコード化可能なソース: