Dosyć dziwne zachowanie podczas analizowania danych JSON przy użyciu Swift 3.
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary
let items:[AnyObject] = (json["items"] as? [AnyObject])!
for item in items {
let id:String = item["id"] as! String
print("ID: (id)")
let info = item["volumeInfo"] as AnyObject
print(info)
let title = info["title"]
print(title)
}
} catch {
print("error thrown")
}
W ten sposób powstaje następujący wynik. Zauważ, że informacja jest opcjonalna, ale jeśli spróbuję ją odwijać, stwierdza, że nie jest to opcja opcjonalna! Ten skrypt się zawiesza let title = info["title"]
W rezultacie nie mogę uzyskać dostępu do klucza tytułu. To zachowanie zmieniło się od czasu Swift 2.
ID: lbvUD6LUyV8C
Optional({
publishedDate = 2002;
publisher = "Sams Publishing";
title = "Java Deployment with JNLP and WebStart";
})
Odpowiedzi:
0 dla odpowiedzi № 1Możesz zrobić coś takiego:
do {
let json = try JSONSerialization.jsonObject(with: data!) as! [String: Any]
let items = json["items"] as! [[String: Any]]
for item in items {
let id = item["id"] as! String
let info = item["volumeInfo"] as! [String: Any]
let title = info["title"] as! String
print(id)
print(info)
print(title)
}
} catch {
print("error thrown: (error)")
}
Mogę zaproponować wycięcie kodu !
wymuszone rozpakowanie (jeśli JSON nie był w oczekiwanej formie, czy naprawdę chcesz, żeby to się zawiesiło?), ale mam nadzieję, że ilustruje to podstawowy pomysł.
0 dla odpowiedzi nr 2
Typ środowiska wykonawczego info
jest Optional<Something>
, ale typem czasu kompilacji (tak jak go rzucasz) jest AnyObject
. W jaki sposób kompilator powinien wiedzieć, że AnyObject
stanie się być Optional<Something>
chyba że powiesz to (w formie obsady)?
Próbować:
let info = item["volumeInfo"] as AnyObject?
Teraz kompilator wie, że to jest Optional<AnyObject>
, więc możesz go rozpakować.
0 dla odpowiedzi № 3
W Swift 3 kompilator musi znać typy wszystkich obiektów indeksowanych, jeśli jest to tablica lub słownik. AnyObject
- który został zmieniony na Any
w Swift 3 - nie wystarcza.
Ponieważ wiesz, że wartość klucza volumeInfo
jest słownikiem obsadzającym go odpowiednio, korzystnie za pomocą opcjonalnych powiązań
let info = item["volumeInfo"] as? [String:Any] {
print(info)
let title = info["title"] as! String
print(title)
}
0 dla odpowiedzi nr 4
Powinno to zrobić:
guard let json = try? JSONSerialization.jsonObject(with: data!, options: []) as! [String: AnyObject],
let items = json["items"] as! Array<AnyObject>? else {
return
}
for item in items {
let id = item["id"] as! String
if let info = item["volumeInfo"] as? [String: AnyObject] {
let title = info["title"] as! String
} else {
// do something
}
}