我从正在从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)}
}
}
5条答案
按热度按时间rdrgkggo1#
下面是一种可能的方法(基于视图模型成员的依赖注入,而不是紧耦合)
g6ll5ycj2#
这个问题是在
@StateObject
在WWDC 2020上推出之前写的。我相信现在你会想使用@StateObject
而不是@ObservedObject
,因为否则你的视图模型可能会被重新初始化很多次(在这种情况下会导致多次网络调用)。我想做和OP完全一样的事情,但是用的是
@StateObject
。这是我的解决方案,不依赖于任何构建配置。View模型协议和实现:
这样,
MovieListView
的外部接口就完全相同了,但是对于预览,您可以使用内部视图定义并覆盖视图模型类型。mwyxok5s3#
对于上面的答案,如果您希望保持您的运输代码库干净,我发现扩展预处理器标志中捕获的类以添加一个方便的init是有效的。
然后也使用预处理器标志修改SwiftUI结构体:
mzmfm0qo4#
因此,尽管@克雷默的解决方案有效,但我遇到了一个挑战,即当我在设备上调试应用程序时,它将加载预览数据,而不是我希望使用的其他“开发”数据。
因此,我通过创建一个名为“Preview”的新构建配置,然后将所有与“preview”相关的数据 Package 到该构建配置中,对解决方案进行了一些扩展。
这让我可以选择在Xcode预览中预览虚拟数据,同时仍然允许我使用设备/模拟器上的开发数据构建和调试开发版本。
所以我的解现在看起来像这样。
这可能不是最好的解决办法,但给了我管理与开发/调试数据分开的预览虚拟数据的灵活性,并且到目前为止已经证明对我的用例效果很好。:)
ioekq8ef5#
我一直在与此斗争,以及想出了以下简单的解决方案。
@StateObject
的初始化是Apple批准的。