Ios 如何在SwiftUI中将数据从ContentView传递到子视图

Ios 如何在SwiftUI中将数据从ContentView传递到子视图,ios,swift,swiftui,Ios,Swift,Swiftui,如果这不合理,请原谅,我完全是Swift的初学者。我正在创建一个配方应用程序,它从API中提取数据并在导航链接中列出。当用户单击配方时,我希望它移动到子视图,并显示API中的信息,如配方名称、图像、成分,并有一个带有网页链接的按钮 我能够通过导航链接将数据拉到列表中。但是,现在我不知道如何使用上面列出的所有信息设置recipe details子视图 这就是我调用API的地方: class RecipeService { func getRecipes(_ completion: @es

如果这不合理,请原谅,我完全是Swift的初学者。我正在创建一个配方应用程序,它从API中提取数据并在导航链接中列出。当用户单击配方时,我希望它移动到子视图,并显示API中的信息,如配方名称、图像、成分,并有一个带有网页链接的按钮

我能够通过导航链接将数据拉到列表中。但是,现在我不知道如何使用上面列出的所有信息设置recipe details子视图

这就是我调用API的地方:


class RecipeService {
    func getRecipes(_ completion: @escaping (Result<[Recipe], Error>) -> ()) {
        let url = URL(string: "http://www.recipepuppy.com/api")!
        URLSession.shared.dataTask(with: url) { (data, _, error) in
            
            if let error = error {
                return completion(.failure(error))
            }
            
            guard let data = data else {
                return completion(.failure(NSError(domain: "", code: -1, userInfo: nil)))
            }
            
            do {
                let response = try JSONDecoder().decode(RecipesResponses.self, from: data)
                completion(.success(response.results))
            } catch {
                completion(.failure(error))
            }
            
        }.resume()
    }
}
这是我的配方视图模型:


class RecipeViewModel: ObservableObject {
    
    @Published var recipes = [Recipe]()
    @Published var isLoading = false
    
    private let service = RecipeService()
    
    init() {
        loadData()
    }
    
    private func loadData() {
        isLoading = true
        service.getRecipes{ [weak self] result in
            DispatchQueue.main.async {
                self?.isLoading = false
                switch result {
                case .failure(let error):
                    print(error.localizedDescription)
                case .success(let recipes):
                    self?.recipes = recipes
                }
            }
        }
    }
    
    
}
这是我列出API响应的视图:


struct RecipesResponses: Codable {
    let title: String
    let version: Double
    let href: String
    let results: [Recipe]
}

struct Recipe: Codable {
    
    
    let title, href, ingredients, thumbnail: String
    
    var detail:  URL {
        URL(string: href)!
    }
    
    var thumb:  URL {
        URL(string: thumbnail)!
    }
}

struct ListView: View {
    @ObservedObject var viewModel = RecipeViewModel()
    
    var body: some View {
        NavigationView {
            List(viewModel.recipes, id: \.href) { recipe in
                NavigationLink (destination: RecipeDetailView()) {
                    HStack{
                        CachedImageView(recipe.thumb)
                            .mask(Circle())
                            .frame(width: 80)
                        VStack(alignment: .leading)  {
                            Text(recipe.title)
                                .font(.largeTitle)
                                .foregroundColor(.black)
                                .padding()
                        }
                    }
                    .buttonStyle(PlainButtonStyle())
                }
            }
            .navigationBarTitle(Text("All Recipes"))
        }
    }
}

struct ListView_Previews: PreviewProvider {
    static var previews: some View {
        ListView()
    }
}
这是我想列出配方详细信息并链接到网页的视图。这就是我努力将API数据拉入的地方:


struct RecipeDetailView: View {
    @ObservedObject var viewModel = RecipeViewModel()
    
    var body: some View {
        Text("Detail View")
    }
}

struct RecipeDetailView_Previews: PreviewProvider {
    static var previews: some View {
        RecipeDetailView()
    }
}

您可以更改
RecipedTailView
以接受
配方
作为参数:

struct RecipeDetailView: View {
    var recipe : Recipe
    
    var body: some View {
        Text(recipe.title)
        Link("Webpage", destination: recipe.detail)
        //etc
    }
}
然后,在
导航链接
中,将
配方
传递给它:

NavigationLink(destination: RecipeDetailView(recipe: recipe)) {
我要警告你的一件事是使用
强制展开
配方中的
URL
s--您应该知道,如果您收到无效/格式不正确的URL,这种类型的展开将使应用程序崩溃


更新,以显示预览的外观:

struct RecipeDetailView_Previews: PreviewProvider {
    static var previews: some View {
        RecipeDetailView(recipe: Recipe(title: "Recipe name", href: "https://google.com", ingredients: "Stuff", thumbnail: "https://linktoimage.com"))
    }
}

我的RecipeDetailView“调用中参数'recipe'缺少参数”中出现错误“每次使用
RecipeDetailView
时,都必须向其传递
recipe
——请参见我在
导航链接中如何做到这一点?无论你在哪里使用它,这都必须发生。因此,在预览中,您还必须传递一个配方(您只需创建一个带有伪值的伪配方即可使用)。有关在预览中提供
配方的示例,请参阅更新的答案