SwiftUI:在ViewModel中预览数据

时间:2020-02-04 12:13:27

标签: swift swiftui

我从从Web加载数据的viewModel加载数据。问题:我想设置一些预览样本数据以在预览窗口中包含内容。目前,我的预览中包含一个空列表,因为我没有提供数据。

我该如何实现?

struct MovieListView: View {

    @ObservedObject var viewModel = MovieViewModel()

    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()
    }
}

class MovieViewModel: ObservableObject{

    private let provider = NetworkManager()

    @Published var movies = [Movie]()

    init() {
       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)}
    }
}

2 个答案:

答案 0 :(得分:7)

这是可行的方法(基于视图模型成员的依赖注入而不是紧密耦合)

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)
        }
    }
}

答案 1 :(得分:0)

进一步回答上面的问题,如果您想保持运输代码库的整洁,我发现可以扩展PreProcessor标志中捕获的类以添加便捷的初始化。

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

然后也使用预处理器标志修改您的SwiftUI结构:

struct MovieListView: View {

   #if DEBUG
   let viewModel: MovieViewModel

   init(viewModel: MovieViewModel = MovieViewModel()){
      self.viewModel = viewModel
   }
   #else
    @ObservedObject 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)
    }
}