Trước hết không bao giờ tải dữ liệu đồng bộ từ một URL từ xa, luôn sử dụng các phương thức không đồng bộ như URLSession
.
'Any' không có thành viên subscript
xảy ra bởi vì trình biên dịch không có ý tưởng về những gì gõ các đối tượng trung gian được (ví dụ currently
trong ["currently"]!["temperature"]
) và kể từ khi bạn đang sử dụng loại bộ sưu tập Foundation như NSDictionary
trình biên dịch không có ý tưởng nào về loại.
Ngoài ra trong Swift 3, bắt buộc phải thông báo cho trình biên dịch về loại tất cả các đối tượng được chỉ định là.
Bạn phải truyền kết quả của việc tuần tự hóa JSON vào loại thực tế.
Mã này sử dụng URLSession
và độc quyền loại bản địa 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()
Để in tất cả các cặp khóa/giá trị của currentConditions
bạn có thể viết
let currentConditions = parsedData["currently"] as! [String:Any]
for (key, value) in currentConditions {
print("\(key) - \(value) ")
}
Một lưu ý về jsonObject(with data
:
Nhiều hướng dẫn (có vẻ như tất cả) gợi ý các tùy chọn .mutableContainers
hoặc .mutableLeaves
hoàn toàn vô nghĩa trong Swift. Hai tùy chọn là các tùy chọn Objective-C kế thừa để gán kết quả cho các đối tượng NSMutable...
. Trong Swift bất kỳ var
iable có thể thay đổi theo mặc định và chuyển bất kỳ tùy chọn nào trong số đó và gán kết quả cho hằng số let
không có tác dụng gì cả. Hơn nữa hầu hết các triển khai không bao giờ đột biến JSON deserialized anyway.
duy nhất (hiếm) tùy chọn đó là hữu ích trong Swift là .allowFragments
đó là cần thiết nếu nếu đối tượng gốc JSON có thể là một kiểu giá trị (String
, Number
, Bool
hoặc null
) chứ không phải là một trong những loại bộ sưu tập (array
hoặc dictionary
). Nhưng thường bỏ qua thông số options
có nghĩa là Không có tùy chọn.
============================================== =============================
một số cân nhắc chung để phân tích JSON
JSON là một văn bản cũng sắp xếp định dạng. Rất dễ đọc chuỗi JSON. Đọc kỹ chuỗi. Chỉ có sáu loại khác nhau - hai loại bộ sưu tập và bốn loại giá trị.
Các loại bộ sưu tập là
- Mảng - JSON: các đối tượng trong dấu ngoặc vuông
[]
- Swift: [Any]
nhưng trong hầu hết trường hợp [[String:Any]]
- điển - JSON: các đối tượng trong dấu ngoặc nhọn
{}
- Swift: [String:Any]
Các kiểu giá trị là
- Chuỗi - JSON: bất kỳ giá trị trong dấu ngoặc kép
"Foo"
, thậm chí "123"
hoặc "false"
- Swift: String
- Số - JSON: giá trị số không trong đôi báo giá
123
hoặc 123.0
- Swift: Int
hoặc Double
- Bool - JSON:
true
hoặc false
không trong dấu ngoặc kép - Swift: true
hoặc false
- rỗng - JSON:
null
- Swift: NSNull
Theo đặc tả JSON tất cả các phím trong các từ điển được yêu cầu là String
.
Về cơ bản nó luôn luôn recommeded sử dụng các ràng buộc bắt buộc để unwrap optionals an toàn
Nếu đối tượng gốc là một từ điển ({}
) đúc loại để [String:Any]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...
và lấy giá trị bằng các phím có (OneOfSupportedJSONTypes
là tập hợp hoặc loại giá trị JSON như được mô tả ở trên.)
if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {
print(foo)
}
Nếu đối tượng gốc là một mảng ([]
) đúc loại để [[String:Any]]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...
và lặp qua mảng với
for item in parsedData {
print(item)
}
Nếu bạn cần một mục tại cụ thể kiểm tra chỉ mục nếu chỉ mục tồn tại
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
let item = parsedData[2] as? OneOfSupportedJSONTypes {
print(item)
}
}
Trong trường hợp hiếm hoi mà các JSON chỉ đơn giản là một trong những loại có giá trị - chứ không phải là một loại bộ sưu tập - bạn phải vượt qua các tùy chọn .allowFragments
và đúc kết quả với các loại giá trị thích hợp ví dụ
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...
Apple đã công bố một bài viết toàn diện trong Blog Swift: Working with JSON in Swift
Bạn có thể đưa dữ liệu mẫu được trả về từ cuộc gọi API của mình không? – User
Vâng, tôi vừa thêm một mẫu các kết quả được in sau khi in (currentConditions). Hy vọng nó giúp. – user2563039