Learn Courses My Dashboard

I am brand new and need help please

I wanted to, for practice add a data call to the recipe module.
The one from GitHub Pages. But I cannot get it to work.
My issue is line 57 I think…In the module where he teaches this,
he does not use a separate file so he just calls it from there. I am using
MVVM practice, so any help would be great!

Network Code

ViewModel Code (to call func)

You say it doesn’t work, but what does that mean? Do you get an error? A blank screen? Incorrect data? It’s hard to help when we don’t know what the problem is.

A couple of issues I can see right off the bat are:

  1. getRemoteData() is an asynchronous function, so you shouldn’t be returning a value from it. Your function will reach the end and return [Recipe]() (i.e., an empty array) before the API call completes. Either update a property directly (if getRemoteData() were a function on your view model) or pass in a completion handler (probably the preferred method here, since getRemoteData() is in a separate DataService class).

  2. getRemoteData() is an asynchronous function, so you shouldn’t call it in a class initializer. The class will finish initializing and won’t have the data you expect it to have since the async call probably won’t have finished yet. Instead, make a call to your API fetching function in an onAppear handler in your View.

Simplified example:

struct FDRecipe: Codable, Identifiable {
    let id = UUID()
    let name: String
    let cuisine: String
    
    enum CodingKeys: CodingKey {
        case name, cuisine
    }
}

class DataService {
    func getRemoteData(completion: @escaping ([FDRecipe]) -> Void) {
        guard let url = URL(string: "https://finidev.github.io/devBox/data.json") else {
            completion([])
            return
        }
        
        URLSession.shared.dataTask(with: URLRequest(url: url)) { data, response, error in
            guard error == nil else {
                return
            }
            
            do {
                let decoder = JSONDecoder()
                let recipeData = try decoder.decode([FDRecipe].self, from: data!)
                completion(recipeData)
                return
            } catch {
                print(error)
            }
        }.resume()
    }
}

class RecipeViewModel: ObservableObject {
    @Published var recipes = [FDRecipe]()
    
    let dataService: DataService
    
    init(dataService: DataService) {
        self.dataService = dataService
    }
    
    func getRemoteData() {
        dataService.getRemoteData { recipes in
            DispatchQueue.main.async {
                self.recipes = recipes
            }
        }
    }
}

struct FDRecipeView: View {
    
    @StateObject var recipeVM = RecipeViewModel(dataService: DataService())
    
    var body: some View {
        List(recipeVM.recipes) { recipe in
            VStack(alignment: .leading) {
                Text(recipe.name)
                    .font(.title)
                    .bold()
                Text(recipe.cuisine)
            }
        }
        .onAppear {
            recipeVM.getRemoteData()
        }
    }
}

Also…

When posting code to these forums, please post the code as text rather than an image. This makes it far easier to read (some of us have aging eyes!) and also makes it possible for other posters to copy/paste the code in order to test solutions and such.

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.

Oh, okay, I am sorry about that.

The issue is nothing is loading. It is just a blank view.

Thank-you for the simplified example.
I was basically using the local version way to create my remote version.
But was following Chris’ example.