Swift 3 中的 JSON 解析
Posted
技术标签:
【中文标题】Swift 3 中的 JSON 解析【英文标题】:JSON Parsing in Swift 3 【发布时间】:2016-07-02 00:42:06 【问题描述】:有没有人能够找到在 Swift 3 中解析 JSON 文件的方法?我已经能够让数据返回,但是在将数据分解为特定字段时我没有成功。我会发布示例代码,但我经历了很多不同的方法都没有成功,并且没有保存任何方法。我要解析的基本格式是这样的。提前致谢。
"Language":
"Field":[
"Number":"976",
"Name":"Test"
,
"Number":"977",
"Name":"Test"
]
【问题讨论】:
您的样本是无效的 JSON。它需要以另一个…
开头和结尾。
我解决了这个问题。但是,它只是在这里错误地粘贴了。我的实际文件格式正确。谢谢
【参考方案1】:
你试过JSONSerialization.jsonObject(with:options:)
吗?
var jsonString = "" +
"\"Language\": " +
"\"Field\":[" +
"" +
"\"Number\":\"976\"," +
"\"Name\":\"Test\"" +
"," +
"" +
"\"Number\":\"977\"," +
"\"Name\":\"Test\"" +
"" +
"]" +
"" +
""
var data = jsonString.data(using: .utf8)!
let json = try? JSONSerialization.jsonObject(with: data)
Swift 有时会产生一些非常奇怪的语法。
if let number = json?["Language"]??["Field"]??[0]?["Number"] as? String
print(number)
JSON 对象层次结构中的所有内容最终都被包装为可选(即AnyObject?
)。 Array<T>
下标返回一个非可选的T
。对于这个包裹在可选数组中的 JSON,数组下标返回 Optional<AnyObject>
。但是,Dictionary<K, V>
下标返回 Optional<V>
。对于这个 JSON,下标返回非常奇怪的外观
Optional<Optional<AnyObject>>
(即AnyObject??
)。
json
是 Optional<AnyObject>
。
json?["Language"]
返回 Optional<Optional<AnyObject>>
。
json?["Language"]??["Field"]
返回一个 Optional<Optional<AnyObject>>
。
json?["Language"]??["Field"]??[0]
返回一个 Optional<AnyObject>
。
json?["Language"]??["Field"]??[0]?["Number"]
返回一个 Optional<Optional<AnyObject>>
。
json?["Language"]??["Field"]??[0]?["Number"] as? String
返回 Optional<String>
。
然后if let
语法使用Optional<String>
生成String
。
最后说明:迭代字段数组如下所示。
for field in json?["Language"]??["Field"] as? [AnyObject] ?? []
if let number = field["Number"] as? String
print(number)
Swift 4 更新
Swift 4 让这一切变得更容易处理。同样,我们将从您的测试数据开始("""
让这变得更好)。
let data = """
"Language":
"Field":[
"Number":"976",
"Name":"Test"
,
"Number":"977",
"Name":"Test"
]
""".data(using: .utf8)!
接下来,我们可以围绕 JSON 中使用的对象定义类。
struct Object: Decodable
let language: Language
enum CodingKeys: String, CodingKey case language="Language"
struct Language: Decodable
let fields: [Field]
enum CodingKeys: String, CodingKey case fields="Field"
struct Field: Decodable
let number: String
let name: String
enum CodingKeys: String, CodingKey case number="Number"; case name="Name"
CodingKeys
枚举是结构属性映射到 JSON 对象成员字符串的方式。此映射由Decodable
自动完成。
现在解析 JSON 很简单。
let object = try! JSONDecoder().decode(Object.self, from: data)
print(object.language.fields[0].name)
for field in object.language.fields
print(field.number)
【讨论】:
我怎样才能开始只提取数字之类的值?这段代码让我进入现场,但我不知道接下来会发生什么。 var data = jsonString.data(使用:.utf8)!让 json = 试试? JSONSerialization.jsonObject(with: data) if let language = json?["Language"] if let field = language?["Field"] print(field) @Nas5296 我更新了关于如何访问 JSON 对象的答案。 非常感谢!这是一种非常奇怪的格式(经典 Swift),但正是我需要的! 除了 Foundation 和 Glibc 之外,你还需要导入什么吗?我得到:error: use of unresolved identifier 'JSONSerialization'
在 Swift 版本 3.0 (swift-3.0-PREVIEW-2) 上。【参考方案2】:
在 Xcode 8 和 Swift 3 中,id
现在导入为 Any
而不是 AnyObject
这意味着JSONSerialization.jsonObject(with: data)
返回Any
。因此,您必须将 json data
转换为特定类型,例如 [String:Any]
。这同样适用于 json 中的下一个字段。
var jsonString = "" +
"\"Language\": " +
"\"Field\":[" +
"" +
"\"Number\":\"976\"," +
"\"Name\":\"Test1\"" +
"," +
"" +
"\"Number\":\"977\"," +
"\"Name\":\"Test2\"" +
"" +
"]" +
"" +
""
var data = jsonString.data(using: .utf8)!
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any]
let language = parsedData["Language"] as! [String:Any]
print(language)
let field = language["Field"] as! [[String:Any]]
let name = field[0]["Name"]!
print(name) // ==> Test1
在实践中,您可能希望在 json 中隐藏一些特定字段。假设它是Field
数组的第一个元素的Name
字段。您可以使用这样的展开链来安全地访问该字段:
var data = jsonString.data(using: .utf8)!
if let json = try? JSONSerialization.jsonObject(with: data) as? [String:Any],
let language = json?["Language"] as? [String:Any],
let field = language["Field"] as? [[String:Any]],
let name = field[0]["Name"] as? String, field.count > 0
print(name) // ==> Test1
else
print("bad json - do some recovery")
您还可以查看 Apple 的 Swift 博客 Working with JSON in Swift
【讨论】:
效果很好!谢谢【参考方案3】:手动将 JSON 推入字符串是一种皮塔饼。为什么不直接将 JSON 放入一个文件并读入呢?
斯威夫特 3:
let bundle = Bundle(for: type(of: self))
if let theURL = bundle.url(forResource: "response", withExtension: "json")
do
let data = try Data(contentsOf: theURL)
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any]
grok(parsedData)
catch
print(error)
【讨论】:
【参考方案4】: override func viewDidLoad()
super.viewDidLoad()
let url=URL(string:"http://api.androidhive.info/contacts/")
do
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["contacts"]
for index in 0...arrJSON.count-1
let aObject = arrJSON[index] as! [String : AnyObject]
names.append(aObject["name"] as! String)
contacts.append(aObject["email"] as! String)
print(names)
print(contacts)
self.tableView.reloadData()
catch
【讨论】:
【参考方案5】:使用可解码协议在 swift 4 中解析 JSON:
我使用您的 json 对象创建了一个模拟文件:
http://www.mocky.io/v2/5a280c282f0000f92c0635e6
这是解析 JSON 的代码:
模型创建:
import UIKit
struct Item : Decodable
// Properties must be the same name as specified in JSON , else it will return nil
var Number : String
var Name : String
struct Language : Decodable
var Field : [Item]
struct Result : Decodable
var Language : Language
如果您不确定 JSON 文件中可能缺少某些内容,您可以在模型中使用 optional。
这是解析逻辑:
class ViewController: UIViewController
let url = "http://www.mocky.io/v2/5a280c282f0000f92c0635e6"
private func parseJSON()
guard let url = URL(string: url) else return
let session = URLSession.shared.dataTask(with: url) (data, response, error) in
guard let data = data else return
guard let result = try? JSONDecoder().decode(Result.self, from: data) else return
print("\n\nResult : \(result)")
session.resume()
override func viewDidLoad()
super.viewDidLoad()
parseJSON()
打印输出:
Result : Result(Language: JSON_Parsing.Language(Field: [JSON_Parsing.Item(Number: "976", Name: "Test"), JSON_Parsing.Item(Number: "977", Name: "Test")]))
This the github Project link. You can check.
【讨论】:
【参考方案6】:以简单的方式使用 Swift 4 进行 JSON 解析
let url = URL(string: "http://mobileappdevelop.co/TIPIT/webservice/get_my_groups?user_id=5")
URLSession.shared.dataTask(with:url!, completionHandler: (data, response, error) in
guard let data = data, error == nil else return
do
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
print(json)
let posts = json["Field"] as? [[String: Any]] ?? []
print(posts)
catch let error as NSError
print(error)
).resume()
【讨论】:
【参考方案7】:使用 SwiftJson 库。我认为它的解析方法非常简单。
let count: Int? = json["Field"].array?.count
if let ct = count
for index in 0...ct-1
let number = json ["Field"][index]["number"].string
let name = json ["Field"][index]["name"].string
....
像这样。
【讨论】:
【参考方案8】:dict =
message = "Login successfully.";
status = 1;
"user_details" = (
dob = "1900-11-18";
email = "rizwan@gmail.com";
gender = male;
name = Rizwan;
nickname = Shaikh;
"profile_pic" = "1483434421.jpeg";
"social_id" = "<null>";
"user_id" = 2;
);
我们可以将 Swift 3 中的上述 json 解析为
var dict2 = dict as! [String : Any]
print(dict);
let demoStr = dict2["message"] as! String
print(demoStr)
let demoArray = dict2["user_details"] as! [Any]
let demoDict = demoArray[0] as! [String:Any]
print(demoDict["dob"]!)
【讨论】:
以上是关于Swift 3 中的 JSON 解析的主要内容,如果未能解决你的问题,请参考以下文章