SwiftUI: Preview with data in ViewModel

Further to the answer above, and if you want to keep your shipping codebase clean, I've found that extending the class captured in PreProcessor flags to add a convenience init works.

#if DEBUG
extension MovieViewModel{
   convenience init(forPreview: Bool = true) {
      self.init()
      //Hard code your mock data for the preview here
      self.movies = [Movie(...)]
   }
}
#endif

Then modify your SwiftUI structs using preprocessor flags as well:

struct MovieListView: View {

   #if DEBUG
   let viewModel: MovieViewModel

   init(viewModel: MovieViewModel = MovieViewModel()){
      self.viewModel = viewModel
   }
   #else
    @StateObject var viewModel = MovieViewModel()
   #endif

    var body: some View {
       List{
        ForEach(viewModel.movies) { movie in
                MovieRow(movie: movie)
                    .listRowInsets(EdgeInsets())
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        MovieListView(viewModel: MovieViewModel(forPreview: true)
    }
}

Here is possible approach (based on dependency-injection of view model members instead of tight-coupling)

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        // create Movie to be previewed inline, say from bundled data
        MovieListView(viewModel: MovieViewModel(provider: nil, movies: [Movie(...)]))
    }
}

class MovieViewModel: ObservableObject {

    private var provider: NetworkManager?

    @Published var movies: [Movie]
    
    // same as before by default, but allows to modify if/when needed explicitly
    init(provider: NetworkManager? = NetworkManager(), movies: [Movie] = []) {
        self.provider = provider
        self.movies = movies

        loadNewMovies()
    }

    func loadNewMovies(){
         provider?.getNewMovies(page: 1) {[weak self] movies in
                print("\(movies.count) new movies loaded")
                self?.movies.removeAll()
                self?.movies.append(contentsOf: movies)
        }
    }
}

Tags:

Swift

Swiftui