'Swift parsing JSON into Table View doesnt work
Hi I have problems to read the Json Data into the TableView. Can anybody help me, its my first time working with it. I know I am doing something wrong, but I cant finde the Solution for my JSON File cause in the Internet they use simple ones..
Here is my JSON:
{
"data":[
{
"title": "Brot",
"desc":[
{
"Name": "Roggenschrot- und Roggenvollkornbrot",
"Menge": "Gramm",
"Kalorie": "2",
"Energiedichte": "Gelb"
},
{
"Name": "Weizenschrot- und Weizenvollkornbrot",
"Menge": "Gramm",
"Kalorie": "2",
"Energiedichte": "Gelb"
},
{
"Name": "Weizenschrot- und Weizenvollkornbrot",
"Menge": "Gramm",
"Kalorie": "2",
"Energiedichte": "Gelb"
},
]
}
]
}
Here is my tableView
import UIKit
class EseenTagebuchTableViewController: UITableViewController {
var result: Result?
var resultItem: ResultItem?
override func viewDidLoad() {
super.viewDidLoad()
parseJSON()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return result?.data.count ?? 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return result?.data[section].title
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if let result = result {
return result.data.count
}
return 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let text = resultItem?.desc?[indexPath.section].Name?[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = text
return cell
}
private func parseJSON() {
guard let path = Bundle.main.path(forResource: "Ernahrungstagebuch", ofType: "json") else {
return
}
let url = URL(fileURLWithPath: path)
do {
let jsonData = try Data(contentsOf: url)
result = try JSONDecoder().decode(Result.self, from: jsonData)
return
}
catch {
print("Error: \(error)")
}
}
}
And here are my Model 1 and after my Model 2
import Foundation
struct Result: Codable {
let data: [ResultItem]
}
struct ResultItem: Codable {
let title: String
let desc: [descItems]?
}
Model 2
import Foundation
struct descItems: Codable {
let Name: String?
let Menge: String?
let Kalorie: Int?
let Energiedichte: String?
}
What am I doing wrong?
Solution 1:[1]
First your json data in your file is not correct, there is an extra "," comma after
the last "Energiedichte": "Gelb" , remove that from your file.
Second your model is not correct, you should have:
struct Result: Codable {
let data: [ResultItem]
}
struct ResultItem: Codable {
let title: String
let desc: [DescItems]?
}
struct DescItems: Codable {
let Name: String?
let Menge: String?
let Kalorie: String? // <-- here not Int?
let Energiedichte: String?
}
Using your code parseJSON() I was able to parse the data without errors.
EDIT-1: if you really want kalories to be Int, try:
struct DescItems: Codable {
let name: String?
let menge: String?
let kalorie: Int? // <-- here
let energiedichte: String?
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
menge = try container.decode(String.self, forKey: .menge)
energiedichte = try container.decode(String.self, forKey: .energiedichte)
let calorie = try container.decode(String.self, forKey: .kalorie) // <-- here
kalorie = Int(calorie) // <-- here
}
enum CodingKeys: String, CodingKey {
case name = "Name"
case menge = "Menge"
case kalorie = "Kalorie"
case energiedichte = "Energiedichte"
}
}
Note the change of case, as per common practice.
Solution 2:[2]
you can also use json parse below code:
func parseJSON() {
let path = Bundle.main.path(forResource: "Ernahrungstagebuch", ofType: "json")
let jsonData = try? NSData(contentsOfFile: path!, options: NSData.ReadingOptions.mappedIfSafe)
let jsonResult: NSDictionary = try! (JSONSerialization.jsonObject(with: jsonData! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary)!
if let data = jsonResult["data"] as? [[String:Any]] {
self.arrPlan = data.map{Day(JSON: $0)!}
// print(arrPlan)
}
}
Try to this code for get data array object and after reload tableview Data.
Solution 3:[3]
You can use this extension to parse json.
import Foundation
extension Bundle {
func decode<T: Decodable>(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
do {
return try decoder.decode(T.self, from: data)
} catch DecodingError.keyNotFound(let key, let context) {
fatalError("Failed to decode \(file) from bundle due to missing key '\(key.stringValue)' not found – \(context.debugDescription)")
} catch DecodingError.typeMismatch(_, let context) {
fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
fatalError("Failed to decode \(file) from bundle due to missing \(type) value – \(context.debugDescription)")
} catch DecodingError.dataCorrupted(_) {
fatalError("Failed to decode \(file) from bundle because it appears to be invalid JSON")
} catch {
fatalError("Failed to decode \(file) from bundle: \(error.localizedDescription)")
}
}
}
And use it like this:
let incomingData = Bundle.main.decode([Your_Model].self, from: "Your_Json_File_name.json")
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Amreliya Dipak |
| Solution 3 | Habin Lama |
