Module 4, Lesson 5, iOS Foundations

Hey Everyone. So I have updated the JSON Data as Chris asked us to, and I tried to implement it on my detail view, but it doesn’t seem to worm and gives me errors every-time I try to preview it. I am posting the screenshots below, so the problem can be seen by whoever is trying to help me out…

Screenshot of my Recipe and Ingredients Model:

Screenshot of my Parsed JSON Data:

Screenshot of the problem I am facing in detail view:

And after I tried to remove (id:.self), like what Chris asked us to do, I am getting this error:

Changed the model to identifiable for ingredients:

and then tried to fix the error:

But I am getting "No exact matches in call to instance method ‘appendInterpolation’’…Kindly help me anyone, on how to fix this issue! Appreciate it.

I think the problem is u r trying to append an ingredient using string interpolation, and not a string itself.

try

Text("- \(item.name)")

Hey Abdul, thanks for the reply…unfortunately that is not working. I am attaching the Screenshot below so you can see…

You can remove the id parameter in forEach as ingredient automatically conforms to identifiable

I removed id from foreach but still I am getting an error, despite the ingredient being conformed to identifiable, as you can see below…

the error:

any idea how to fix this? searched up a lot on YouTube and google, but no answer

I see that you have item.ingredients in the text view instead of item.name. Could you try changing it?

If it still doesn’t work, can you post your code as text instead of a screenshot, wrapping your code in backticks ```

Ingredients needs to conform to Hashable

You can’t just write Text("- \(item.ingredients)") because it is an object.

You could write Text(" - \(item.ingredients.name)")

Also be sure to check your code to Chris’ code! You may have missed something somewhere

Thank you so much, I got what needed to be fixed…but now I am facing another problem…everytime I hit preview on my detail view, the app crashes. Below is the screenshot

The error…

The description of the error…

But My recipes.json is exactly the same as Chris’ but his data is being decoded, but mine is not being decoded. in module 2, the complete list app, with only the navigation link and navigation view, the data from recipes.json was being parsed, but in this case its not working…any idea what to do, help is really appreciated!

What does the json look like vs the Swift model? If it isn’t being parsed something isn’t written correctly in the model

My JSON Data:

[
{
“name”: “Eggplant Parmesan”,
“featured”: false,
“image” : “eggplant parmesan”,
“description”: “Baked eggplant with bread crumbs and lots of cheese. Delicious!”,
“prepTime”: “25 minutes”,
“cookTime”: “35 minutes”,
“totalTime”: “1 hour”,
“servings”: 10,
“highlights”: [
“Vegetarian”,
“Healthy”,
“Easy clean-up”
],
“ingredients”: [
{“name”: “Eggplant, peeled and thinly sliced”, “num”: 3},
{“name”: “Large eggs”, “num”: 2},
{“name”: “Italian seasoned bread crumbs”, “num”: 4, “unit”: “cup”},
{“name”: “Spaghetti sauce”, “num”: 6, “unit”: “cup”},
{“name”: “Mozarella cheese, shredded”, “num”: 2, “unit”: “cup”},
{“name”: “Parmesan cheese, grated”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Dried basil”, “num”: 1, “denom”: 2, “unit”: “teaspoon”}
],
“directions”: [
“Preheat oven to 350 degrees F (175 degrees C).”,
“Dip eggplant slices in egg, then in bread crumbs. Place in a single layer on a baking sheet. Bake in preheated oven for 5 minutes on each side.”,
“In a 9x13 inch baking dish spread spaghetti sauce to cover the bottom. Place a layer of eggplant slices in the sauce. Sprinkle with mozzarella and Parmesan cheeses. Repeat with remaining ingredients, ending with the cheeses. Sprinkle basil on top.”,
“Bake in preheated oven for 35 minutes, or until golden brown.”
]
},
{
“name”: “Mushroom Risotto”,
“featured”: true,
“image” : “mushroom risotto”,
“description”: "Authentic Italian-style risotto cooked the slow and painful way, but oh so worth it. ",
“prepTime”: “20 minutes”,
“cookTime”: “30 minutes”,
“totalTime”: “50 minutes”,
“servings”: 6,
“highlights”: [
“Creamy”,
“Vegetarian”
],
“ingredients”: [
{“name”: “Chicken broth”, “num”: 6, “unit”: “cup”},
{“name”: “Olive oil”, “num”: 3, “unit”: “tablespoon”},
{“name”: “Portobello mushrooms”, “num”: 1, “unit”: “pound”},
{“name”: “White mushrooms”, “num”: 1, “unit”: “pound”},
{“name”: “Shallots, diced”, “num”: 2},
{“name”: “Arborio rice”, “num”: 3, “denom”: 2, “unit”: “cup”},
{“name”: “Dry white wine”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Sea salt”, “unit”: “To taste”},
{“name”: “Black pepper”, “unit”: “To taste”},
{“name”: “Chives, finely chopped”, “num”: 3, “unit”: “tablespoon”},
{“name”: “Butter”, “num”: 4, “unit”: “tablespoon”},
{“name”: “Parmesan cheese”, “num”: 1, “denom”: 3, “unit”: “cup”}
],
“directions”: [
“In a saucepan, warm the broth over low heat.”,
“Warm 2 tablespoons olive oil in a large saucepan over medium-high heat. Stir in the mushrooms, and cook until soft, about 3 minutes. Remove mushrooms and their liquid, and set aside.”,
“Add 1 tablespoon olive oil to skillet, and stir in the shallots. Cook 1 minute. Add rice, stirring to coat with oil, about 2 minutes. When the rice has taken on a pale, golden color, pour in wine, stirring constantly until the wine is fully absorbed. Add 1/2 cup broth to the rice, and stir until the broth is absorbed. Continue adding broth 1/2 cup at a time, stirring continuously, until the liquid is absorbed and the rice is al dente, about 15 to 20 minutes.”,
“Remove from heat, and stir in mushrooms with their liquid, butter, chives, and parmesan. Season with salt and pepper to taste.”
]
},
{
“name”: “Baked Teriyaki Chicken”,
“featured”: false,
“image” : “chicken teriyaki”,
“description”: “A sweet and savory favourite.”,
“prepTime”: “30 minutes”,
“cookTime”: “1 hour”,
“totalTime”: “1 hour 30 minutes”,
“servings”: 6,
“highlights”: [
“Low fat”,
“Easy prep”
],
“ingredients”: [
{“name”: “Cornstarch”, “num”: 1, “unit”: “tablespoon”},
{“name”: “Cold water”, “num”: 1, “unit”: “tablespoon”},
{“name”: “White sugar”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Soy sauce”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Cider vinegar”, “num”: 1, “denom”: 4, “unit”: “cup”},
{“name”: “Garlic, minced”, “num”: 1, “unit”: “clove”},
{“name”: “Ground ginger”, “num”: 1, “denom”: 2, “unit”: “teaspoon”},
{“name”: “Black pepper”, “num”: 1, “denom”: 4, “unit”: “teaspoon”},
{“name”: “Boneless, skinless chicken thighs”, “num”: 12, “unit”: “thigh”}
],
“directions”: [
“In a small saucepan over low heat, combine the cornstarch, cold water, sugar, soy sauce, vinegar, garlic, ginger and ground black pepper. Let simmer, stirring frequently, until sauce thickens and bubbles.”,
“Preheat oven to 425 degrees F (220 degrees C).”,
“Place chicken pieces in a lightly greased 9x13 inch baking dish. Brush chicken with the sauce. Turn pieces over, and brush again.”,
“Bake in the preheated oven for 30 minutes. Turn pieces over, and bake for another 30 minutes, until no longer pink and juices run clear. Brush with sauce every 10 minutes during cooking.”
]
},
{
“name”: “Lasagna”,
“featured”: false,
“image” : “lasagna”,
“description”: “Layers of goodness in this cheesy delight.”,
“prepTime”: “30 minutes”,
“cookTime”: “2 hours 30 minutes”,
“totalTime”: “3 hours”,
“servings”: 12,
“highlights”: [
“Cheesy”,
“Oven meal”
],
“ingredients”: [
{“name”: “Italian Sausage”, “num”: 1, “unit”: “pound”},
{“name”: “Ground beef”, “num”: 3, “denom”: 4, “unit”: “pound”},
{“name”: “Diced onion”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Garlic”, “num”: 2, “unit”: “clove”},
{“name”: “Crushed tomatoes”, “num”: 28, “unit”: “ounce”},
{“name”: “Tomato paste”, “num”: 12, “unit”: “ounce”},
{“name”: “Tomato sauce”, “num”: 13, “unit”: “ounce”},
{“name”: “Water”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “White sugar”, “num”: 2, “unit”: “tablespoon”},
{“name”: “Dried basil leaves”, “num”: 3, “denom”: 2, “unit”: “tablespoon”},
{“name”: “Fennel seeds”, “num”: 1, “denom”: 2, “unit”: “teaspoon”},
{“name”: “Italian seasoning”, “num”: 1, “unit”: “teaspoon”},
{“name”: “Salt”, “num”: 3, “denom”: 2, “unit”: “teaspoon”},
{“name”: “Black pepper”, “num”: 1, “denom”: 4, “unit”: “teaspoon”},
{“name”: “Fresh parsley, chopped”, “num”: 4, “unit”: “tablespoon”},
{“name”: “Lasagna noodles”, “num”: 12},
{“name”: “Ricotta cheese”, “num”: 16, “unit”: “ounce”},
{“name”: “Egg”, “num”: 1},
{“name”: “Mozarella cheese”, “num”: 3, “denom”: 4, “unit”: “pound”},
{“name”: “Parmesan cheese”, “num”: 3, “denom”: 4, “unit”: “cup”}
],
“directions”: [
“In a Dutch oven, cook sausage, ground beef, onion, and garlic over medium heat until well browned. Stir in crushed tomatoes, tomato paste, tomato sauce, and water. Season with sugar, basil, fennel seeds, Italian seasoning, 1 teaspoon salt, pepper, and 2 tablespoons parsley. Simmer, covered, for about 1 1/2 hours, stirring occasionally.”,
“Bring a large pot of lightly salted water to a boil. Cook lasagna noodles in boiling water for 8 to 10 minutes. Drain noodles, and rinse with cold water. In a mixing bowl, combine ricotta cheese with egg, remaining parsley, and 1/2 teaspoon salt.”,
“Preheat oven to 375 degrees F (190 degrees C).”,
“To assemble, spread 1 1/2 cups of meat sauce in the bottom of a 9x13 inch baking dish. Arrange 6 noodles lengthwise over meat sauce. Spread with one half of the ricotta cheese mixture. Top with a third of mozzarella cheese slices. Spoon 1 1/2 cups meat sauce over mozzarella, and sprinkle with 1/4 cup Parmesan cheese. Repeat layers, and top with remaining mozzarella and Parmesan cheese. Cover with foil: to prevent sticking, either spray foil with cooking spray, or make sure the foil does not touch the cheese.”,
“Bake in preheated oven for 25 minutes. Remove foil, and bake an additional 25 minutes. Cool for 15 minutes before serving.”
]
},
{
“name”: “Pad Thai”,
“featured”: true,
“image” : “pad thai”,
“description”: “A delicious noodle dish!”,
“prepTime”: “15 minutes”,
“cookTime”: “15 minutes”,
“totalTime”: “30 minutes”,
“servings”: 4,
“highlights”: [
“Spicy”,
“Fast”,
“Make it your own”
],
“ingredients”: [
{“name”: “Flat rice noodles”, “num”: 8, “unit”: “ounce”},
{“name”: “Fish sauce”, “num”: 3, “unit”: “tablespoon”},
{“name”: “Fresh lime juice”, “num”: 1, “denom”: 4, “unit”: “cup”},
{“name”: “White sugar”, “num”: 1, “unit”: “tablespoon”},
{“name”: “Oyster sauce”, “num”: 2, “unit”: “tablespoon”},
{“name”: “Asian chile pepper sauce”, “num”: 3, “denom”: 2, “unit”: “tablespoon”},
{“name”: “Chicken stock”, “num”: 1, “denom”: 4, “unit”: “cup”},
{“name”: “Vegetable oil”, “num”: 1, “denom”: 4, “unit”: “cup”},
{“name”: “Chopped garlic”, “num”: 1, “unit”: “tablespoon”},
{“name”: “Medium shrimp, peeled and deveined”, “num”: 8, “unit”: “ounce”},
{“name”: “Boneless, skinless chicken breast, cubed”, “num”: 8, “unit”: “ounce”},
{“name”: “Large eggs, beaten”, “num”: 2},
{“name”: “Bean sprouts”, “num”: 3, “unit”: “cup”},
{“name”: “Green onions, chopped”, “num”: 6},
{“name”: “Unsalted, roasted peanuts, chopped”, “num”: 2, “unit”: “tablespoon”},
{“name”: “Fresh cilantro, chopped”, “num”: 1, “denom”: 4, “unit”: “cup”},
{“name”: “Lime wedges”, “num”: 8}
],
“directions”: [
“Fill a large bowl with hot tap water and place the noodles in it to soak for 20 minutes.”,
“In a small bowl, stir together the fish sauce, lime juice, sugar, oyster sauce, 2 teaspoons of the chile sauce and chicken stock. Set aside.”,
“Heat a wok or large skillet over high heat and add vegetable oil. When the oil is hot, stir in garlic and cook for about 10 seconds. Add shrimp and chicken; cook, stirring constantly until shrimp is opaque and chicken is cooked through, 5 to 7 minutes.”,
“Move everything in the wok out to the sides and pour the eggs in the center. Cook and stir the eggs until firm. Add the noodles to the wok and pour in the sauce. Cook, stirring constantly, until the noodles are tender. Add a bit more water if needed to finish cooking the noodles. Stir in 3 cups of bean sprouts and green onions. Remove from the heat and garnish with chopped peanuts. Taste for seasoning, adjusting the spice or lime juice if needed.”,
“Serve garnished with fresh cilantro and remaining bean sprouts and lime wedges on the side.”
]
},
{
“name”: “Monterey Chicken”,
“featured”: true,
“image” : “monterey chicken”,
“description”: “Classic Monterey Chicken, worth the time!”,
“prepTime”: “45 minutes”,
“cookTime”: “15 minutes”,
“totalTime”: “1 hour”,
“servings”: 4,
“highlights”: [
“Melt in your mouth”,
“Gluten free”
],
“ingredients”: [
{“name”: “Skinless, boneless chicken breast”, “num”: 4, “unit”: “half”},
{“name”: “Teriyaki marinade sauce”, “num”: 1, “unit”: “cup”},
{“name”: “Bacon”, “num”: 1, “denom”: 2, “unit”: “pound”},
{“name”: “Butter”, “num”: 2, “unit”: “tablespoon”},
{“name”: “Onion, cut into long slices”, “num”: 1},
{“name”: “Fresh mushrooms, coarsely chopped”, “num”: 8, “unit”: “ounce”},
{“name”: “Mozarella cheese”, “num”: 4, “unit”: “slice”}
],
“directions”: [
“To Marinate: Place chicken in a nonporous glass dish or bowl. Pour marinade over chicken and toss to coat. Cover and refrigerate to marinate for 1 to 2 hours.”,
“Preheat oven to 350 degrees F (175 degrees C).”,
“Place chicken in a 9x13 inch baking dish and bake preheated oven for 20 to 30 minutes, or until cooked through and juices run clear. Meanwhile, place bacon in a large, deep skillet. Cook over medium high heat until evenly brown. Drain and set aside.”,
“In same skillet, melt butter over medium high heat. Saute onion, bell pepper and mushrooms for about 3 to 5 minutes. Add remaining 1/3 cup of marinade and simmer until soft. Drain and set onion mixture aside.”,
“Top baked chicken with bacon strips. Add onion mixture and top each breast with a slice of cheese. Bake for another 10 to 15 minutes, or until cheese is melted and bubbly.”
]
},
{
“name”: “Twice-baked potatoes”,
“featured”: false,
“image” : “baked potato”,
“description”: “A fantastic starchy side.”,
“prepTime”: “30 minutes”,
“cookTime”: “1 hour 30 minutes”,
“totalTime”: “2 hours”,
“servings”: 4,
“highlights”: [
“Comfort food”,
“Filling”
],
“ingredients”: [
{“name”: “Russet potatoes”, “num”: 4},
{“name”: “Vegetable oil”, “num”: 2, “unit”: “teaspoon”},
{“name”: “Butter”, “num”: 3, “unit”: “tablespoon”},
{“name”: “Green onion, minced”, “num”: 1, “unit”: “tablespoon”},
{“name”: “Salt and pepper”, “unit”: “To taste”},
{“name”: “Cayenne pepper”, “num”: 1, “unit”: “pinch”},
{“name”: “Cheddar cheese, shredded”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Heavy cream”, “num”: 1, “denom”: 2, “unit”: “cup”},
{“name”: “Egg yolk”, “num”: 1},
{“name”: “Butter, melted”, “num”: 1, “unit”: “tablespoon”},
{“name”: “Paprika”, “num”: 1, “unit”: “teaspoon”}
],
“directions”: [
“Preheat oven to 400 degrees F (200 degrees C). Line a baking sheet with aluminum foil.”,
“Rub potatoes with vegetable oil and place on the prepared baking sheet.”,
“Bake in the preheated oven until a paring knife easily inserts into the center of a potato, about 1 hour. Set aside to cool until easy to handle, about 10 minutes.”,
“Cut 1/3 off each potato lengthwise. Scoop flesh from each potato to within about 1/8-inch of the skins. Transfer flesh to a bowl.”,
“Combine potato flesh with butter and green onion; stir until butter is melted evenly into potato. Add salt, black pepper, cayenne pepper, and cheese; stir until cheese is melted. Pour cream and egg yolk into potato mixture; mix to combine. Season with salt to taste.”,
“Place small piece of potato skin inside the bottom of each larger potato shell. Fill each potato with an equal amount of cheese mixture. Gently press the surface of the filling with a fork to create texture. Brush tops with melted butter and sprinkle with paprika.”,
“Bake stuffed potatoes until golden brown on top, 20 to 30 minutes.”
]
}
]

My Swift Model along with parsed JSON data:

import Foundation

struct Recipe: Codable, Identifiable {
var id = UUID()
let name: String
let featured: Bool
let image, Description, prepTime, cookTime: String
let totalTime: String
let servings: Int
let highlights: [String]
let ingredients: [Ingredient]
let directions: [String]

static let allRecipes : [Recipe] = Bundle.main.Decode(file: "recipes.json")

enum CodingKeys: String, CodingKey {
    case name, featured, image
    case Description = "description"
    case prepTime, cookTime, totalTime, servings, highlights, ingredients, directions
}

}

struct Ingredient: Codable, Identifiable {
var id = UUID()
let name: String
let num: Int?
let unit: String?
let denom: Int?
}

extension Bundle {
func Decode < X : Decodable > (file: String) → X {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError(“could not find (file) in project!”)
}

    guard let data = try? Data(contentsOf: url) else {
        fatalError("could not open \(file) in project!")
    }
    
    let decoder = JSONDecoder()
    guard let loadedData = try? decoder.decode(X.self, from: data) else {
        fatalError("could not retrieve \(file) from project!")
    }
    
    return loadedData
}

}

Can you print the contents of “data” before you try to decode it?

Also, shouldn’t the message be “could not decode data…”, rather than “could not retrieve…”?

hey, thanks for replying…may I ask you, how should I go about printing the data? Like what’s the code I need to write in order to print it before decoding

I’m no expert here, but usually just saying print(data) should do it. This only works while you’re running under Xcode, either with the simulator or a physical device, depending on what you have selected.

The output shows up in the lower right section of the Xcode console.

@Amandal2002

Make sure that your Models.swift file has no errors in the struct definitions for each of the properties. It should be like this:

struct Recipe: Identifiable, Decodable {
    var id: UUID?
    var name: String
    var category: String
    var featured: Bool
    var image: String
    var description: String
    var prepTime: String
    var cookTime: String
    var totalTime: String
    var servings: Int
    var highlights: [String]
    var ingredients: [Ingredient]
    var directions: [String]
}

struct Ingredient: Identifiable, Decodable {
    var id: UUID?
    var name: String
    var num: Int?
    var denom: Int?
    var unit: String?
}