Module2: Challenge 7

I am kind of confused, in lesson 7 video the instructor creates the structure recipe for the model, and recipe model class for the view model. In the structure he never defined a particular init override method and is able to pass name and cuisine into the Recipe object. However when I try to create the same thing with pizza for the challenge it doesn’t allow me to do that and says argument passed to call that takes no arguments.

I don’t understand why creating the same code for the structure succeeds in the lesson but not for the challenge. Any advice?

Here is the current view model code.

//
//  PizzaModel.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import Foundation

class PizzaModel{
    var pizzas = [Pizza]()
    
    init(){
        pizzas.append(Pizza(name: "Original", topping1: "Pepperoni", topping2: "Black Olives", topping3: "Mushrooms"))
    }
}

The current model.

//
//  Pizza.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import Foundation

struct Pizza{
    private var name = ""
    private var topping1 = ""
    private var topping2 = ""
    private var topping3 = ""
    
    /*mutating func buildPizza(pname:String,top1:String,top2:String,top3:String){
        name = pname
        topping1 = top1
        topping2 = top2
        topping3 = top3
    }*/
}

The current view code.

//
//  ContentView.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

It’s because you have defined the properties of Pizza as private, so they are not accessible from outside the struct. As a result, the memberwise initializer that the Swift compiler creates for you looks like Pizza(), without any parameters.

In order to use

Pizza(name: "Original", topping1: "Pepperoni", topping2: "Black Olives", topping3: "Mushrooms")

you would need to either:

  1. Remove the private access from the four properties of Pizza, or
  2. Write your own initializer that takes those parameters and assigns them to the properties.

I just removed the private access identifier, but now as I pasted the code I got ** var** pizza appearing here. I don’t know what is causing it, as the ** don’t exist in my code normally just when pasted here. I also added a bit of code to the view.

//

// Pizza.swift

// Module2Challenge7

//

// Created by Eric Beecroft on 10/19/21.

//

import Foundation

struct Pizza{

var name = ""

var topping1 = ""

var topping2 = ""

var topping3 = ""

}

Current Model

//
//  PizzaModel.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import Foundation

class PizzaModel{
    var pizzas = [Pizza]()
    
    init(){
        pizzas.append(Pizza(name: "Original", topping1: "Pepperoni", topping2: "Black Olives", topping3: "Mushrooms"))
        pizzas.append(Pizza(name: "Zaparoni", topping1: "Pepperoni", topping2: "Jalpinos", topping3: "Lightning"))
        pizzas.append(Pizza(name: "AquaSpecial", topping1: "Seacumbers", topping2: "Shrimp", topping3: "Anchovies"))
    }
}

Current View

//
//  ContentView.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import SwiftUI

struct ContentView: View {
    var model = PizzaModel()
    var body: some View {
        List{
            VStack{
                
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

The **var** stuff is because you were pasting code in without enclosing it in a code fence. Since Xcode bolds keywords like var, they get pasted into Discourse with bold markup: **var**.

Make sure you post code into a fenced block and that won’t happen. I thinkn you knnow how to do that, since your code is formatted correctly above, but just in case:

To post your code as text, place three backticks ``` on the line before your code and three backticks ``` on the line after your code so that it will be formatted properly. You can also highlight an entire code block and click the </> button on the toolbar to wrap the block for you.


So, does your code work now? You didn’t say.

So here is what I got so far for challenge 7. I am getting can’t find forEach in scope error.

//
//  ContentView.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import SwiftUI

struct ContentView: View {
    var pizzas = PizzaModel()
    var body: some View {
        VStack{
            List(pizzas){
                
                
                forEach(pizzas){
                    Text(pizza[index].name)
                    Text(pizza[index].topping1)
                    Text(pizza[index].topping2)
                    Text(pizza[index].topping3)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Because it’s ForEach, not forEach. Capitalization matters.

It’s

// forEach(pizzas) {
ForEach(pizzas) {

I fixed it now. I am getting issues with pizza not being in scope, can’t convert pizzaModel to int, and pizzaModel needs to conform to random access collection.

//
//  ContentView.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import SwiftUI

struct ContentView: View {
    var pizzas = PizzaModel()
    var body: some View {
        VStack{
            List(pizzas){
                
                
                ForEach(pizzas){_ in
                    Text(pizza[index].name)
                    Text(pizza[index].topping1)
                    Text(pizza[index].topping2)
                    Text(pizza[index].topping3)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

I fixed it now.

Assuming you are using the same PizzaModel you posted up thread…

List(pizzas) {

should be:

List {

Since you use a ForEach to actually list your items, you don’t need to also list them using List.

ForEach(pizzas) { _ in

needs to be:

ForEach(pizzas.pizzas) { pizza in

in order to access the array of pizzas inside the PizzaModel. This will also solve your "pizza is not in scope" problem.

As for "can’t convert PizzaModel to Int", that’s because you shouldn’t be using [index] to access individual pizzas; that’s what the { pizza in part is for. And where does index come from anyway?

So just do this:

Text(pizza.name)
Text(pizza.topping1)
Text(pizza.topping2)
Text(pizza.topping3)

Oh, and you also need to either a) make the Pizza struct Identifiable, like this:

struct Pizza: Identifiable {
    let id = UUID() //not the only way to do it, but probably the easiest
    //... other pizza properties
}

Or b) change ForEach to explicitly indicate what property should be used to uniquely identify the pizzas, like so:

ForEach(pizzas.pizzas, id: \.name) { pizza in
...
}

I changed the pizzas variable to pmodel to make it easier for me to tell the difference between what is the model and what variable is the structure. So now the food items now appear on the screen.

//
//  ContentView.swift
//  Module2Challenge7
//
//  Created by Eric Beecroft on 10/19/21.
//

import SwiftUI

struct ContentView: View {
    var pmodel = PizzaModel()
    var body: some View {
        VStack{
            ForEach(pmodel.pizzas, id: \.name){ pizza in
                Spacer()
                Text(pizza.name)
                HStack{Spacer()
                Text(pizza.topping1)
                    Spacer()
                Text(pizza.topping2)
                    Spacer()
                Text(pizza.topping3)
                    Spacer()
                }
                Spacer()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}