Her şeyden önce hiçbir zaman uzak bir URL'den eşzamanlı olarak veri yükleme , her zaman gibi eşzamansız yöntemler kullanın URLSession.
"Herhangi biri" nin alt simge üyesi yoktur
derleyicinin ara nesnelerin (örneğin currentlyiçinde ["currently"]!["temperature"]) ne tür olduğuna dair hiçbir fikri olmadığı ve Foundation koleksiyon türlerini şu şekilde kullandığınız için oluşur.NSDictionary hakkında hiçbir fikri olmadığı ve derleyici hakkında hiçbir fikri olmadığı için oluşur.
Ek olarak, Swift 3'te derleyiciye her şeyin türü hakkında bilgi vermek gerekir. abone olunan nesnelerin .
JSON serileştirmesinin sonucunu gerçek türe çevirmelisiniz.
Bu kod kullanımları URLSessionve münhasıran Swift yerli türleri
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()
Tüm anahtar / değer çiftlerini yazdırmak için currentConditionsyazabilirsin
let currentConditions = parsedData["currently"] as! [String:Any]
for (key, value) in currentConditions {
print("\(key) - \(value) ")
}
Aşağıdakilerle ilgili bir not jsonObject(with data:
Pek çok (hepsi görünüyor) öğretici .mutableContainersveya .mutableLeavesSwift'de tamamen saçma olan seçenekler öneriyor . İki seçenek, sonucu NSMutable...nesnelere atamak için kullanılan eski Objective-C seçenekleridir . varSwift'de herhangi bir iable varsayılan olarak değiştirilebilir ve bu seçeneklerden herhangi birini geçirmenin ve sonucu bir letsabite atamanın hiçbir etkisi yoktur. Dahası, uygulamaların çoğu zaten serileştirilmemiş JSON'u asla değiştirmiyor.
Swift yararlıdır sadece (nadir) bir seçenektir .allowFragmentsJSON kök nesnesi, bir değer türü olabilir, eğer varsa gerekli olan ( String, Number, Boolveya null) ziyade toplama türlerinden biri ( arrayveya dictionary). Ancak normalde, seçenek yokoptions anlamına gelen parametreyi atlayın .
================================================== =========================
JSON'u ayrıştırmak için bazı genel hususlar
JSON, iyi düzenlenmiş bir metin biçimidir. Bir JSON dizesini okumak çok kolaydır. Dizeyi dikkatlice okuyun . Yalnızca altı farklı tür vardır - iki koleksiyon türü ve dört değer türü.
Koleksiyon türleri
- Dizi - JSON: köşeli parantez içindeki nesneler
[]- Swift: [Any]ancak çoğu durumda[[String:Any]]
- Sözlük - JSON: kaşlı ayraçlar içindeki nesneler
{}- Swift:[String:Any]
Değer türleri
- Dize - JSON: çift tırnak herhangi bir değer
"Foo", hatta "123"ya "false"- Swift:String
- Sayı - JSON: çift tırnak içinde olmayan sayısal değerler
123veya 123.0- Swift: IntveyaDouble
- Bool - JSON:
trueveya çift tırnak içinde false değil - Swift: trueveyafalse
- null - JSON:
null- Swift:NSNull
JSON belirtimine göre sözlüklerdeki tüm anahtarların olması gerekir String.
Temel olarak, isteğe bağlı bağları güvenli bir şekilde açmak için her zaman isteğe bağlı bağlamaların kullanılması önerilir
Kök nesne bir sözlükse ( {}), türü[String:Any]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...
ve değerleri anahtarlara göre alın ( OneOfSupportedJSONTypesyukarıda açıklandığı gibi JSON koleksiyonu veya değer türüdür.)
if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {
print(foo)
}
Kök nesne bir dizi ise ( []), türü[[String:Any]]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...
ve dizi boyunca yineleyin
for item in parsedData {
print(item)
}
Belirli bir dizinde bir öğeye ihtiyacınız varsa, dizinin mevcut olup olmadığını da kontrol edin
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
let item = parsedData[2] as? OneOfSupportedJSONTypes {
print(item)
}
}
JSON'un bir koleksiyon türü yerine sadece değer türlerinden biri olduğu nadir durumlarda, .allowFragmentsseçeneği iletmeniz ve sonucu uygun değer türüne çevirmeniz gerekir, örneğin
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...
Apple, Swift Blog'da kapsamlı bir makale yayınladı: Swift'de JSON ile Çalışma
================================================== =========================
Swift 4 + 'da Codableprotokol, JSON'u doğrudan yapılara / sınıflara ayrıştırmak için daha uygun bir yol sağlar.
Örneğin, soruda verilen JSON örneği (biraz değiştirildi)
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}
"""
yapının kodu çözülebilir Weather. Swift türleri yukarıda açıklananlarla aynıdır. Birkaç ek seçenek var:
- Bir'yi temsil eden dizelerin
URLkodu doğrudan URL.
timeTam sayı olarak deşifre edilebilir Dateile dateDecodingStrategy .secondsSince1970.
- snaked_cased JSON tuşları dönüştürülebilir CamelCase ile
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)
}
Diğer Kodlanabilir kaynaklar: