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 currently
iç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ı URLSession
ve 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 currentConditions
yazabilirsin
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 .mutableContainers
veya .mutableLeaves
Swift'de tamamen saçma olan seçenekler öneriyor . İki seçenek, sonucu NSMutable...
nesnelere atamak için kullanılan eski Objective-C seçenekleridir . var
Swift'de herhangi bir iable varsayılan olarak değiştirilebilir ve bu seçeneklerden herhangi birini geçirmenin ve sonucu bir let
sabite 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 .allowFragments
JSON kök nesnesi, bir değer türü olabilir, eğer varsa gerekli olan ( String
, Number
, Bool
veya null
) ziyade toplama türlerinden biri ( array
veya 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
123
veya 123.0
- Swift: Int
veyaDouble
- Bool - JSON:
true
veya çift tırnak içinde false
değil - Swift: true
veyafalse
- 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 ( OneOfSupportedJSONTypes
yukarı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, .allowFragments
seç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 Codable
protokol, 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
URL
kodu doğrudan URL
.
time
Tam sayı olarak deşifre edilebilir Date
ile 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: