sjl*_*nth 4 xcode ios swift swiftui
我有一个 SwiftUI 应用程序,它使用公共 API 按名称下载鸡尾酒数据,但我对 SwiftUI 不太熟悉,而且我看不到在详细信息视图文件中初始化视图模型的方法。
\n这是我的 swift 文件 ifcocktail 数据结构;
\nstruct Drinks: Decodable {\n var cocktails: [Cocktail]\n}\n\nstruct Cocktail: Decodable, Identifiable {\n var id: String {\n return idDrink\n }\n let idDrink: String\n let strDrink: String\n let strDrinkThumb: String\n let strAlcoholic: String\n let strGlass: String\n let strInstructions: String\n let strIngredient1: String?\n let strIngredient2: String?\n let strIngredient3: String?\n let strIngredient4: String?\n let strIngredient5: String?\n let strIngredient6: String?\n let strIngredient7: String?\n let strIngredient8: String?\n let strIngredient9: String?\n let strIngredient10: String?\n let strIngredient11: String?\n let strIngredient12: String?\n}\n
Run Code Online (Sandbox Code Playgroud)\n这是我的 NetworkManager 类;
\nclass NetworkManager {\n \n func fetchData(_ urlString: String, completion: @escaping (Drinks, Bool) -> Void) {\n guard let url = URL(string: urlString) else { return }\n var drinks: Drinks?\n let session = URLSession(configuration: .default)\n let task = session.dataTask(with: url) { data, response, error in\n if error == nil {\n let decoder = JSONDecoder()\n guard let safeData = data else { return }\n do {\n drinks = try decoder.decode(Drinks.self, from: safeData)\n completion(drinks!, false)\n } catch let error {\n print(error.localizedDescription)\n if error.localizedDescription == "The data couldn\xe2\x80\x99t be read because it is missing." {\n completion(drinks ?? Drinks(cocktails: [Cocktail]()), true)\n } else {\n print(error.localizedDescription)\n }\n }\n }\n }\n task.resume()\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n这是我的 ViewModel 类;
\nclass ViewModel: ObservableObject {\n \n let networkManager = NetworkManager()\n var urlString: String\n @Published var drinks: Drinks = Drinks(cocktails: [Cocktail]())\n @Published var dataIsFound: Bool = true\n \n init(urlString: String) {\n self.urlString = urlString\n FetchData()\n }\n \n func FetchData() {\n \n networkManager.fetchData(urlString) { results, error in\n DispatchQueue.main.async {\n self.drinks = results\n self.dataIsFound = !error\n }\n }\n }\n
Run Code Online (Sandbox Code Playgroud)\n这是我的 DetailsView 结构;
\nstruct DetailsView: View {\n \n @StateObject var viewModel = ViewModel()\n \n var body: some View {\n \n List(viewModel.drinks.cocktails) { cocktail in\n\n VStack(alignment: .center) {\n HStack(alignment: .center) {\n Text(cocktail.strDrink + " -")\n .navigationTitle("Cocktail by first letter")\n .frame(alignment: .center)\n Text(cocktail.strAlcoholic)\n .frame(alignment: .center)\n }\n \n WebImage(url: URL(string: cocktail.strDrinkThumb))\n .resizable()\n .frame(width: UIScreen.main.bounds.width - 20.0, height: UIScreen.main.bounds.width - 20.0, alignment: .center)\n \n \n Text("~ Ingredients List ~\\n").frame(alignment: .center)\n \n ForEach(viewModel.buildIngredients(cocktail), id: \\.self) { ingredient in\n Text(ingredient)\n }\n \n Text("\\n~ Recipe Instructions ~\\n\\n")\n \n Text(cocktail.strInstructions + "\\n").fixedSize(horizontal: false, vertical: true)\n }\n } \n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n任何帮助,将不胜感激。谢谢。
\njn_*_*pdx 15
这是一种常见的模式,使用ViewModel()
来初始化然后fetchData
调用onAppear
:
class ViewModel: ObservableObject {
let networkManager = NetworkManager()
@Published var drinks: Drinks = Drinks(cocktails: [Cocktail]())
@Published var dataIsFound: Bool = true
func fetchData(urlString: String) {
//call fetchData on network manager
}
}
struct DetailsView: View {
var urlString : String
@StateObject private var viewModel = ViewModel()
var body: some View {
List(viewModel.drinks.cocktails) { cocktail in
//list content
}
.onAppear {
viewModel.fetchData(urlString: urlString)
}
}
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用您的View'
s init
。在这种情况下,@StateObject
调用 的 init 并将其urlString
传递到View
. 因为StateObject
'swrappedValue
参数使用自动闭包,并且仅在将视图添加到层次结构中时才运行,因此您不必担心视图模型将在init
每个View
.
class ViewModel: ObservableObject {
let networkManager = NetworkManager()
@Published var drinks: Drinks = Drinks(cocktails: [Cocktail]())
@Published var dataIsFound: Bool = true
init(urlString: String) {
fetchData(urlString: urlString)
}
func fetchData(urlString: String) {
//call fetchData on network manager
}
}
struct DetailsView: View {
@StateObject private var viewModel : ViewModel
init(urlString: String) {
_viewModel = StateObject(wrappedValue: ViewModel(urlString: urlString))
}
var body: some View {
//body content
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7265 次 |
最近记录: |