在 Swift 中解析 JSON 5
Parse JSON in Swift 5
我正在尝试为 JSON 文件编写一个类似于此的通用解析器。
{
"BA": {
"name": "Bert Andries",
"age": 40,
"likes": ["Food"]
},
...
}
我想 return Dictionary<String, User>
其中 User
具有属性 name
、age
和 likes
。这就是我现在拥有的。
import Foundation
struct JsonHelper {
static func parseJsonString<T: Decodable>(jsonString: String, entityType: T.Type) -> Dictionary<String, T> {
let jsonData = jsonString.data(using: .utf8)!
let items = try! JSONDecoder().decode([entityType].self, from: jsonData)
return items
}
static func parseJsonFile<T: Decodable>(file: String, entityType: T.Type) -> Dictionary<String, T> {
if let filepath = Bundle.main.path(forResource: file, ofType: "json") {
if let contents = try? String(contentsOfFile: filepath) {
return self.parseJsonString(jsonString: contents, entityType: entityType)
}
}
}
}
解决方案
根据 bcal 的回答,我将 struct
重写为这个。
import Foundation
struct JsonHelper {
static func parseJsonString<T: Decodable>(jsonString: String, entityType: T.Type) -> Dictionary<String, T>? {
if let jsonData = jsonString.data(using: .utf8) {
return try? JSONDecoder().decode(Dictionary<String, T>.self, from: jsonData)
}
return nil
}
static func parseJsonFile<T: Decodable>(file: String, entityType: T.Type) -> Dictionary<String, T>? {
if let filepath = Bundle.main.path(forResource: file, ofType: "json") {
if let contents = try? String(contentsOfFile: filepath) {
return self.parseJsonString(jsonString: contents, entityType: entityType)
}
}
return nil
}
}
而且我可以这样使用它。
if let users = JsonHelper.parseJsonFile(file: "users", entityType: User.self) {
if let user = dictionary["BA"] {
print(user.name)
}
}
User结构可以这样写。由于属性后面的 ?
,即使 JSON 对象中缺少这些属性,解码也会成功。
struct User: Codable {
let name: String?
let age: Int?
let likes: [String]?
}
Dictionary
符合Encodable
和Decodable
,所以JSONDecoder
可以和Dictionary<String, User>
类型一起使用。
解码您的 JSON 对象 ...
let jsonString = """
{
"BA": {
"name": "Bert Andries",
"age": 40,
"likes": ["FN"]
},
"FN": {
"name": "Frans Niemen",
"age": 44,
"likes": ["BA"]
},
"SA": {
"name": "Sandra Andries",
"age": 35,
"likes": ["BA", "FN"]
}
}
"""
struct User: Codable {
let name: String?
let age: Int?
let likes: [String]?
}
func decode(jsonString: String) throws -> Dictionary<String, User>? {
guard let jsonData = jsonString.data(using: .utf8) else {
return nil
}
return try JSONDecoder().decode(Dictionary<String, User>.self, from: jsonData)
}
let dict = try? decode(jsonString: jsonString)
print("\(String(describing: dict))")
我正在尝试为 JSON 文件编写一个类似于此的通用解析器。
{
"BA": {
"name": "Bert Andries",
"age": 40,
"likes": ["Food"]
},
...
}
我想 return Dictionary<String, User>
其中 User
具有属性 name
、age
和 likes
。这就是我现在拥有的。
import Foundation
struct JsonHelper {
static func parseJsonString<T: Decodable>(jsonString: String, entityType: T.Type) -> Dictionary<String, T> {
let jsonData = jsonString.data(using: .utf8)!
let items = try! JSONDecoder().decode([entityType].self, from: jsonData)
return items
}
static func parseJsonFile<T: Decodable>(file: String, entityType: T.Type) -> Dictionary<String, T> {
if let filepath = Bundle.main.path(forResource: file, ofType: "json") {
if let contents = try? String(contentsOfFile: filepath) {
return self.parseJsonString(jsonString: contents, entityType: entityType)
}
}
}
}
解决方案
根据 bcal 的回答,我将 struct
重写为这个。
import Foundation
struct JsonHelper {
static func parseJsonString<T: Decodable>(jsonString: String, entityType: T.Type) -> Dictionary<String, T>? {
if let jsonData = jsonString.data(using: .utf8) {
return try? JSONDecoder().decode(Dictionary<String, T>.self, from: jsonData)
}
return nil
}
static func parseJsonFile<T: Decodable>(file: String, entityType: T.Type) -> Dictionary<String, T>? {
if let filepath = Bundle.main.path(forResource: file, ofType: "json") {
if let contents = try? String(contentsOfFile: filepath) {
return self.parseJsonString(jsonString: contents, entityType: entityType)
}
}
return nil
}
}
而且我可以这样使用它。
if let users = JsonHelper.parseJsonFile(file: "users", entityType: User.self) {
if let user = dictionary["BA"] {
print(user.name)
}
}
User结构可以这样写。由于属性后面的 ?
,即使 JSON 对象中缺少这些属性,解码也会成功。
struct User: Codable {
let name: String?
let age: Int?
let likes: [String]?
}
Dictionary
符合Encodable
和Decodable
,所以JSONDecoder
可以和Dictionary<String, User>
类型一起使用。
解码您的 JSON 对象 ...
let jsonString = """
{
"BA": {
"name": "Bert Andries",
"age": 40,
"likes": ["FN"]
},
"FN": {
"name": "Frans Niemen",
"age": 44,
"likes": ["BA"]
},
"SA": {
"name": "Sandra Andries",
"age": 35,
"likes": ["BA", "FN"]
}
}
"""
struct User: Codable {
let name: String?
let age: Int?
let likes: [String]?
}
func decode(jsonString: String) throws -> Dictionary<String, User>? {
guard let jsonData = jsonString.data(using: .utf8) else {
return nil
}
return try JSONDecoder().decode(Dictionary<String, User>.self, from: jsonData)
}
let dict = try? decode(jsonString: jsonString)
print("\(String(describing: dict))")