Booysenberry
Booysenberry

Reputation: 255

How to initialise one property with another during initialisation process - SwiftUI

I'm building an app that fetches data from the The Movie Database API and presents a List of movies by genre.

In my view model I have a function that calls the api and makes the data available via an observable object.

import Foundation

class MovieListViewModel: ObservableObject {
    
    @Published var movies = [Movie]()
    
    private var fetchedMovies = [MovieList]()
    
    var page = 1
    
    func fetchMovies(genre: Int) {
        
        WebService().getMoviesByGenre(genre: genre, page: page) { movie in
            
            if let movie = movie {
                
                self.fetchedMovies.append(movie)
                
                for movie in movie.movies {
                    
                  
                        self.movies.append(movie)
                
                }
            }
        }
        page += 1
        print(page)
    }
}

Inside the view, I'm using onAppear to call the function and pass the genre id (Int) received from the previous view. This all works as expected.

import SwiftUI

struct MovielistView: View {
    
    @ObservedObject private var movielistVM = MovieListViewModel()
    
    var genre: GenreElement
    
    var body: some View {
        
        List {
            
            ...
            
            }
            
        }.onAppear {
            self.movielistVM.fetchMovies(genre: self.genre.id)
            
        }
        .navigationBarTitle(genre.name)
    }
}

The problem is because I'm using onAppear, the api is being hit/the view refreshed every time the user navigates back to the view.

Ideally, I'd like to call the api once during the initialising of the view model but because the genre property hasn't been initialised yet, it can't pass the parameter to the view model.

I'v tried this (below) but get the error 'self' used before all stored properties are initialized

import SwiftUI

struct MovielistView: View {
    
    @ObservedObject private var movielistVM = MovieListViewModel()
    
    var genre: GenreElement
    
    init() {
        movielistVM.fetchMovies(genre: genre.id) // Error here
    }
    
    var body: some View {
        
        List {
            
            ...
            
        }
        .navigationBarTitle(genre.name)
    }
}

Any help would be appreciated.

Upvotes: 0

Views: 400

Answers (1)

Frankenstein
Frankenstein

Reputation: 16361

Add a genre parameter for the init and initialize the genre property of MovielistView before using it:

struct MovielistView: View {
    var genre: GenreElement
    //...
    init(genre: GenreElement) {
        self.genre = genre
        movielistVM.fetchMovies(genre: genre.id)
    }
    //...
}

Upvotes: 1

Related Questions