Парсинг JSON через Codable. Swift
Здесь уже есть похожий вопрос Парсинг JSON по протоколу Decodable на Swift 4, но там как я понял у автора все заработало, а у меня в идентичной ситуации не хочет. Вот и вопрос, как это сделать правильно и чтоб заработало.
Вот кусочек моего JSON:
"67": {
"name": "Аксессуары",
"sortOrder": "29",
"image": "image/catalog/im2017/4.png",
"iconImage": "image/catalog/style/modile/acc_cat.png",
"iconImageActive": "image/catalog/style/modile/acc_cat_active_s.png",
"subcategories": [
{
"id": "311",
"iconImage": "",
"sortOrder": "2",
"name": "Маски, повязки на лицо",
"type": "Category"
Ссылка на весь JSON на всякий случай : http://blackstarshop.ru/index.php?route=api/v1/categories
А вот мой код:
struct PreCategory: Codable {
var a: Category
var b: Category
var c: Category
var d: Category
var e: Category
var f: Category
var g: Category
var h: Category
var i: Category
var j: Category
enum CodingKeys: String, CodingKey {
case a = "67"
case b = "68"
case c = "69"
case d = "73"
case e = "74"
case f = "123"
case g = "156"
case h = "165"
case i = "233"
case j = "0"
}
}
struct Category: Codable {
var name: String
var sortOrder: String
var image: String
var iconImage: String
var iconImageActive: String
var subcategories: [Subcategory]
enum CodingKeys: String, CodingKey {
case name
case sortOrder
case image
case iconImage
case iconImageActive
case subcategories
}
}
struct Subcategory: Codable {
var id: String
var iconImage: String
var sortOrder: String
var name: String
var type: String
enum CodingKeys: String, CodingKey {
case id
case iconImage
case sortOrder
case name
case type
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
guard let url = URL(string: "http://blackstarshop.ru/index.php?route=api/v1/categories") else {return}
let request = URLRequest(url: url)
_ = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments){
//print(json)
}
do {
let categoryJSON = try JSONDecoder().decode(PreCategory.self, from: data!)
print(categoryJSON)
} catch let error {
print(error)
}
}.resume()
}
}
А итогом всего этого безобразия является ошибка:
typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "67", intValue: nil), CodingKeys(stringValue: "subcategories", intValue: nil), _JSONKey(stringValue: "Index 10", intValue: 10), CodingKeys(stringValue: "id", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))
Заранее спасибо всем, кто откликнулся.
Ответы (1 шт):
where are few type mismatches in server response. For example:
"id":"217", //String
"id":67, //Int
To resolve the issue, you can fix types on server-side, or you can use some special type on client side, which can parse both int and string, for example:
enum NumerableString: Codable {
case string(String)
case int(Int)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
if let x = try? container.decode(Int.self) {
self = .int(x)
return
}
throw DecodingError.typeMismatch(NumerableString.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for NumerableString"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let x):
try container.encode(x)
case .int(let x):
try container.encode(x)
}
}
func getStringValue() -> String {
switch self {
case .string(let x):
return x
case .int(let x):
return String(x)
}
}
}
and change yur code to:
struct Category: Codable {
var name: String
var sortOrder: NumerableString
......
struct Subcategory: Codable {
var id: NumerableString
var iconImage: String
var sortOrder: NumerableString