SwiftUI应用中如何在DetailsView中正确初始化ViewModel
问题原因
你的ViewModel自定义了要求传入urlString参数的构造器,但当前DetailsView中初始化ViewModel时未传入任何参数,同时你调用的buildIngredients方法也没有在ViewModel中实现,这两处是主要问题。
修复步骤
- 先给
ViewModel补全缺失的buildIngredients方法,用于拼接配料列表:
class ViewModel: ObservableObject { let networkManager = NetworkManager() var urlString: String @Published var drinks: Drinks = Drinks(cocktails: [Cocktail]()) @Published var dataIsFound: Bool = true init(urlString: String) { self.urlString = urlString fetchData() // 方法名小写开头符合Swift命名规范 } func fetchData() { networkManager.fetchData(urlString) { results, error in DispatchQueue.main.async { self.drinks = results self.dataIsFound = !error } } } // 新增配料拼接方法 func buildIngredients(_ cocktail: Cocktail) -> [String] { var ingredients = [String]() let mirror = Mirror(reflecting: cocktail) for child in mirror.children { if let key = child.label, key.hasPrefix("strIngredient"), let value = child.value as? String, !value.isEmpty { ingredients.append(value) } } return ingredients } }
- 修改
DetailsView,添加接收外部url的属性,初始化ViewModel时传入url:
struct DetailsView: View { // 新增属性,用于接收上层页面传入的查询接口地址 let queryUrl: String // 声明ViewModel存储属性 @StateObject private var viewModel: ViewModel // 自定义构造器完成ViewModel初始化 init(queryUrl: String) { self.queryUrl = queryUrl // @StateObject需要通过下划线访问底层存储属性完成初始化 _viewModel = StateObject(wrappedValue: ViewModel(urlString: queryUrl)) } var body: some View { // 增加加载、空状态提示优化使用体验 Group { if !viewModel.dataIsFound { Text("未找到匹配的鸡尾酒数据") } else if viewModel.drinks.cocktails.isEmpty { ProgressView("加载中...") } else { List(viewModel.drinks.cocktails) { cocktail in VStack(alignment: .center) { HStack(alignment: .center) { Text(cocktail.strDrink + " -") .frame(alignment: .center) Text(cocktail.strAlcoholic) .frame(alignment: .center) } WebImage(url: URL(string: cocktail.strDrinkThumb)) .resizable() .scaledToFit() .frame(maxWidth: .infinity) .padding(.horizontal, 10) Text("~ Ingredients List ~\n").frame(alignment: .center) ForEach(viewModel.buildIngredients(cocktail), id: \.self) { ingredient in Text(ingredient) } Text("\n~ Recipe Instructions ~\n\n") Text(cocktail.strInstructions + "\n").fixedSize(horizontal: false, vertical: true) } } // navigationTitle需要挂载在导航容器下的根视图上,放在内层Text无效 .navigationTitle("Cocktail by first letter") } } } }
- 上层跳转页面调用示例:
如果要查询首字母为a的鸡尾酒,跳转时传入对应接口地址即可:
NavigationLink("查看首字母A的鸡尾酒") { DetailsView(queryUrl: "https://www.thecocktaildb.com/api/json/v1/1/search.php?f=a") }
内容的提问来源于stack exchange,提问作者sjlearmonth
相关产品推荐
相关产品推荐

