/ / Dziwne zachowanie opcji w Swift 3 - json, swift3, opcjonalnie

Dziwne zachowanie opcji w Swift 3 - json, swift3, opcjonalnie

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 № 1

Moż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
}
}