ครั้งแรกของทั้งหมดไม่เคยโหลดข้อมูลพร้อมกันจากระยะไกล URL ที่URLSessionใช้วิธีการไม่ตรงกันเสมอเช่น
"ใด ๆ " ไม่มีสมาชิกตัวห้อย
เกิดขึ้นเนื่องจากคอมไพลเลอร์ไม่ทราบว่าวัตถุกลางเป็นประเภทใด (ตัวอย่างเช่นcurrentlyใน["currently"]!["temperature"]) และเนื่องจากคุณใช้ชนิดคอลเล็กชัน Foundation เช่นNSDictionaryคอมไพเลอร์จึงไม่มีความคิดเกี่ยวกับประเภทเลย
นอกจากนี้ใน 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 สองตัวเลือกคืออ็อพชัน Objective-C ดั้งเดิมเพื่อกำหนดผลลัพธ์ให้กับNSMutable...อ็อบเจ็กต์ ใน Swift variable ใด ๆจะไม่แน่นอนโดยค่าเริ่มต้นและการส่งผ่านตัวเลือกใด ๆ เหล่านั้นและการกำหนดผลลัพธ์เป็นletค่าคงที่จะไม่มีผลเลย ยิ่งไปกว่านั้นการใช้งานส่วนใหญ่จะไม่กลายพันธุ์ JSON ที่ไม่ได้กำหนดค่ามาตรฐานอีกต่อไป
เท่านั้น (หายาก) ตัวเลือกซึ่งจะเป็นประโยชน์ในสวิฟท์.allowFragmentsซึ่งเป็นสิ่งจำเป็นถ้าหากวัตถุราก JSON อาจจะเป็นประเภทค่า ( String, Number, Boolหรือnull) มากกว่าหนึ่งในชนิดของคอลเลกชัน ( arrayหรือdictionary) แต่ปกติละเว้นoptionsพารามิเตอร์ซึ่งหมายความว่าไม่มีตัวเลือก
================================================== =========================
ข้อควรพิจารณาทั่วไปบางประการในการแยกวิเคราะห์ JSON
JSON เป็นรูปแบบข้อความที่มีการจัดเรียงอย่างดี การอ่านสตริง JSON นั้นง่ายมาก อ่านสตริงอย่างระมัดระวัง มีเพียงหกประเภทเท่านั้น - ประเภทคอลเลกชันสองประเภทและประเภทมูลค่าสี่ประเภท
ประเภทคอลเลกชันคือ
- Array - JSON: ออบเจ็กต์ในวงเล็บเหลี่ยม
[]- Swift: [Any]แต่ในกรณีส่วนใหญ่[[String:Any]]
- พจนานุกรม - JSON: วัตถุในวงเล็บปีกกา
{}- Swift:[String:Any]
ประเภทค่าคือ
- สตริง - JSON: ค่าใด ๆ ในราคาคู่
"Foo"แม้"123"หรือ"false"- สวิฟท์:String
- Number - JSON: ค่าตัวเลขที่ไม่อยู่ในเครื่องหมายคำพูดคู่
123หรือ123.0- Swift: IntหรือDouble
- Bool - JSON:
trueหรือfalse ไม่อยู่ในเครื่องหมายคำพูดคู่ - Swift: 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 เป็นเพียงประเภทค่าหนึ่งแทนที่จะเป็นประเภทคอลเลกชันคุณต้องส่งผ่าน.allowFragmentsตัวเลือกและส่งผลลัพธ์ไปยังประเภทค่าที่เหมาะสมเช่น
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...
Apple ได้เผยแพร่บทความที่ครอบคลุมใน Swift Blog: Working with JSON in Swift
================================================== =========================
ใน 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}
"""
สามารถถอดรหัสเข้าไปที่ Weatherstruct ประเภทของ Swift นั้นเหมือนกับที่อธิบายไว้ข้างต้น มีตัวเลือกเพิ่มเติมบางประการ:
- สตริงที่แสดงถึง
URLสามารถถอดรหัสได้โดยตรงเป็นURL.
timeจำนวนเต็มสามารถถอดรหัสเป็นด้วยDatedateDecodingStrategy .secondsSince1970
- snaked_casedคีย์ JSON สามารถแปลงเป็นcamelCaseด้วย
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)
}
แหล่งที่มาที่สามารถเข้ารหัสอื่น ๆ :