I am new to Swift and I am having an issue with an application that I am developing. I am trying to parse some JSON provided by an API and I am encountering an issue where the program fails to decode the JSON into Swift Types provided by a struct.
Recipe_API_Caller.swift
import Foundation
import UIKit
class call_Edamam_API{
func fetch(matching query: [String: String], completion: @escaping ([Recipe]?)-> Void){
let baseURL = URL(string: "https://api.edamam.com/search")!
guard let url = baseURL.withQueries(query)
else{
completion(nil)
print("Cannot build URL")
return
}
print(url)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
let Recipe_Decoder = JSONDecoder()
if let data = data,
let Recipes = try?
Recipe_Decoder.decode(Hit.self, from: data){
completion(Recipes.hits)
}
else{
print("JSON Decoding Error")
completion(nil)
return
}
}
task.resume()
}
}
Recipe.swift
import Foundation
struct Hit: Codable{
let hits: [Recipe]
}
struct Recipe: Codable{
var name: String
var image: URL
var Ingredient_List: Array<String>
var See_More_URL: URL
enum Recipe_Coding_Keys: String, CodingKey{
case name = "label"
case image = "image"
case Ingredient_List = "ingredientLines"
case See_More_URL = "url"
}
init(from decoder: Decoder) throws {
let recipe_Info = try decoder.container(keyedBy: Recipe_Coding_Keys.self)
name = try recipe_Info.decode(String.self, forKey: Recipe_Coding_Keys.name)
image = try recipe_Info.decode(URL.self, forKey: Recipe_Coding_Keys.image)
Ingredient_List = try recipe_Info.decode(Array.self, forKey: Recipe_Coding_Keys.Ingredient_List)
See_More_URL = try recipe_Info.decode(URL.self, forKey: Recipe_Coding_Keys.See_More_URL)
print(name)
print(See_More_URL)
}
}
RecipeTableViewController.swift
import UIKit
class RecipeTableViewController: UITableViewController {
@IBAction func downloadButtonTouched(_ sender: Any) {
}
let recipe_API_Call = call_Edamam_API()
var returned_Recipes = [Recipe]()
override func viewDidLoad() {
super.viewDidLoad()
print(searchTermImport)
fetchRecipes()
}
func fetchRecipes(){
self.returned_Recipes = []
self.tableView.reloadData()
let query: [String: String] = [
"q": "Chicken",
"app_id": "xxx",
"app_key": "xxx"
]
recipe_API_Call.fetch(matching: query, completion: {(returned_Recipes) in
DispatchQueue.main.async {
if let returned_Recipes = returned_Recipes{
self.returned_Recipes = returned_Recipes
self.tableView.reloadData()
}
else{
print("Fetch Error")
}
}
})
}
func configureTable(cell: UITableViewCell, forItemAt indexPath: IndexPath){
let returned_Recipe = returned_Recipes[indexPath.row]
cell.textLabel?.text = returned_Recipe.name
let network_task = URLSession.shared.dataTask(with: returned_Recipe.image){ (data, response, error)
in
guard let Image_dest = data else{
return
}
DispatchQueue.main.async {
let image = UIImage(data: Image_dest)
cell.imageView?.image = image
}
}
network_task.resume()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return returned_Recipes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "recipeCell", for: indexPath)
// Configure the cell...
configureTable(cell: cell, forItemAt: indexPath)
return cell
}
Part of JSON retrieved from URL
{
"q" : "Chicken",
"from" : 0,
"to" : 10,
"more" : true,
"count" : 168106,
"hits" : [ {
"recipe" : {
"uri" : "http://www.edamam.com/ontologies/edamam.owl#recipe_b79327d05b8e5b838ad6cfd9576b30b6",
"label" : "Chicken Vesuvio",
"image" : "https://www.edamam.com/web-img/e42/xxx.jpg",
"source" : "Serious Eats",
"url" : "http://www.seriouseats.com/recipes/2011/12/chicken-vesuvio-recipe.html",
"shareAs" : "http://www.edamam.com/recipe/chicken-vesuvio-b79327d05b8e5b838ad6cfd9576b30b6/chicken",
"yield" : 4.0,
"dietLabels" : [ "Low-Carb" ],
"healthLabels" : [ "Sugar-Conscious", "Peanut-Free", "Tree-Nut-Free" ],
"cautions" : [ "Sulfites" ],
"ingredientLines" : [ "1/2 cup olive oil", "5 cloves garlic, peeled", "2 large russet potatoes, peeled and cut into chunks", "1 3-4 pound chicken, cut into 8 pieces (or 3 pound chicken legs)", "3/4 cup white wine", "3/4 cup chicken stock", "3 tablespoons chopped parsley", "1 tablespoon dried oregano", "Salt and pepper", "1 cup frozen peas, thawed" ],
Upon running the app, the program receives data from the API call, but it is unable to decode it into Swift Types that I created in Recipe.swift. I receive the "JSON Decoding Error" that I created in Recipe_API_Caller.swift. I thought my issue may have been that I didn't have another struct for the "hits" part of the JSON file, but I added that and it is still giving me the error.
I can print the created URL and input it into a web browser and browse the JSON file manually so I know my URL and API key are working properly. Xcode does not provide me with any official errors as to what is happening, so I am unsure of how to proceed from here. I would appreciate any advice that you all could provide!