ครั้งแรกของทั้งหมดไม่เคยโหลดข้อมูลพร้อมกันจากระยะไกล 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 var
iable ใด ๆจะไม่แน่นอนโดยค่าเริ่มต้นและการส่งผ่านตัวเลือกใด ๆ เหล่านั้นและการกำหนดผลลัพธ์เป็น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}
"""
สามารถถอดรหัสเข้าไปที่ Weather
struct ประเภทของ Swift นั้นเหมือนกับที่อธิบายไว้ข้างต้น มีตัวเลือกเพิ่มเติมบางประการ:
- สตริงที่แสดงถึง
URL
สามารถถอดรหัสได้โดยตรงเป็นURL
.
time
จำนวนเต็มสามารถถอดรหัสเป็นด้วยDate
dateDecodingStrategy
.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)
}
แหล่งที่มาที่สามารถเข้ารหัสอื่น ๆ :