【发布时间】:2021-09-24 20:51:44
【问题描述】:
我在发出 get 请求时收到以下错误:
Thread 3: Fatal error: Unexpectedly found nil while unwrapping an Optional value
数据模型+获取请求模型如下:
struct Get: Codable, Identifiable {
var id = UUID()
var meals: [String: String?]
}
class Api {
func getData(completion: @escaping ([Get]) -> ()) {
guard let url = URL(string: "www.themealdb.com/api/json/v1/1/random.php") else {return}
URLSession.shared.dataTask(with: url) { (data, _, _) in
let get = try! JSONDecoder().decode([Get].self, from: data!)
DispatchQueue.main.async {
completion(get)
}
}
.resume()
}
}
示例视图:
struct apitestview: View {
@State var getRecipe: [Get] = []
var body: some View {
List(getRecipe) { get in
Text("placeholder") //once the data is received, how will I display the data here?
}
.onAppear() {
Api().getData { (get) in
self.getRecipe = get
}
}
}
}
此外,一旦收到数据,如何在视图中显示它?嵌套的 JSON 结构让我感到困惑。我很新收到请求。它不需要显示在列表中,它可以是一个巨大的Text()元素。
以下是示例 JSON 对象:
{
"meals": [
{
"idMeal": "52858",
"strMeal": "New York cheesecake",
"strDrinkAlternate": null,
"strCategory": "Dessert",
"strArea": "American",
"strInstructions": "Position an oven shelf in the middle of the oven. Preheat the oven to fan 160C/conventional 180C/gas 4. Line the base of a 23cm springform cake tin with parchment paper. For the crust, melt the butter in a medium pan. Stir in the biscuit crumbs and sugar so the mixture is evenly moistened. Press the mixture into the bottom of the pan and bake for 10 minutes. Cool on a wire rack while preparing the filling.\r\nFor the filling, increase the oven temperature to fan 200C/conventional 240C/gas 9. In a table top mixer fitted with the paddle attachment, beat the soft cheese at medium-low speed until creamy, about 2 minutes. With the mixer on low, gradually add the sugar, then the flour and a pinch of salt, scraping down the sides of the bowl and the paddle twice.\r\nSwap the paddle attachment for the whisk. Continue by adding the vanilla, lemon zest and juice. Whisk in the eggs and yolk, one at a time, scraping the bowl and whisk at least twice. Stir the 284ml carton of soured cream until smooth, then measure 200ml/7fl oz (just over 3⁄4 of the carton). Continue on low speed as you add the measured soured cream (reserve the rest). Whisk to blend, but don't over-beat. The batter should be smooth, light and somewhat airy.\r\nBrush the sides of the springform tin with melted butter and put on a baking sheet. Pour in the filling - if there are any lumps, sink them using a knife - the top should be as smooth as possible. Bake for 10 minutes. Reduce oven temperature to fan 90C/conventional 110C/gas 1⁄4 and bake for 25 minutes more. If you gently shake the tin, the filling should have a slight wobble. Turn off the oven and open the oven door for a cheesecake that's creamy in the centre, or leave it closed if you prefer a drier texture. Let cool in the oven for 2 hours. The cheesecake may get a slight crack on top as it cools.\r\nCombine the reserved soured cream with the 142ml carton, the sugar and lemon juice for the topping. Spread over the cheesecake right to the edges. Cover loosely with foil and refrigerate for at least 8 hours or overnight.\r\nRun a round-bladed knife around the sides of the tin to loosen any stuck edges. Unlock the side, slide the cheesecake off the bottom of the tin onto a plate, then slide the parchment paper out from underneath.",
"strMealThumb": "https://www.themealdb.com/images/media/meals/swttys1511385853.jpg",
"strTags": "Desert,Dairy,Pudding,Cake,Breakfast",
"strYoutube": "https://www.youtube.com/watch?v=tspdJ6hxqnc",
"strIngredient1": "Butter",
"strIngredient2": "Sour Cream",
"strIngredient3": "Sugar",
"strIngredient4": "Cream Cheese",
"strIngredient5": "Caster Sugar",
"strIngredient6": "Plain Flour",
"strIngredient7": "Lemon Juice",
"strIngredient8": "Eggs",
"strIngredient9": "Sour Cream",
"strIngredient10": "Sour Cream",
"strIngredient11": "Caster Sugar",
"strIngredient12": "Lemon Juice",
"strIngredient13": "",
"strIngredient14": "",
"strIngredient15": "",
"strIngredient16": "",
"strIngredient17": "",
"strIngredient18": "",
"strIngredient19": "",
"strIngredient20": "",
"strMeasure1": "85g",
"strMeasure2": "140g",
"strMeasure3": "1tbsp",
"strMeasure4": "900g",
"strMeasure5": "250g",
"strMeasure6": "3 tbs",
"strMeasure7": "1 ½ teaspoons",
"strMeasure8": "3 Large",
"strMeasure9": "250ml",
"strMeasure10": "150ml",
"strMeasure11": "1 tbsp",
"strMeasure12": "2 tsp",
"strMeasure13": "",
"strMeasure14": "",
"strMeasure15": "",
"strMeasure16": "",
"strMeasure17": "",
"strMeasure18": "",
"strMeasure19": "",
"strMeasure20": "",
"strSource": "https://www.bbcgoodfood.com/recipes/2869/new-york-cheesecake",
"strImageSource": null,
"strCreativeCommonsConfirmed": null,
"dateModified": null
}
]
}
不久前我确实问过一个类似的问题,这帮助我在这个问题上指明了正确的方向。我仍然无法弄清楚这一点。有什么想法吗?
附加信息:
nil 引用被抛出的位置的图像:
编辑 2 - 发布新版本的代码:
class Api {
func getData(completion: @escaping (Get) -> ()) {
guard let url = URL(string: "www.themealdb.com/api/json/v1/1/random.php") else {return}
URLSession.shared.dataTask(with: url) { (data, _, _) in
let get = try! JSONDecoder().decode(Get.self, from: data!)
DispatchQueue.main.async {
completion(get)
}
}
.resume()
}
}
struct apitestview: View {
@State var getRecipe: Get
var body: some View {
//List(getRecipe) { get in
Text("placeholder")
//}
.onAppear() {
Api().getData { (get) in
self.getRecipe = get
}
}
}
}
【问题讨论】:
-
您能否提供更多关于抛出 nil 值的上下文。我的猜测是“数据”变量是 nil,但你强制解开它。
-
另外你解码的 [Get].self 应该是 Get.self。您不会返回一系列膳食字典,而只是返回膳食字典。
-
贾斯汀,我已经添加了投掷位置的图像。
-
我会先将
decode([Get].self...)更改为decode(Get.self...(请参阅我上面的评论。这绝对是问题的一部分。此外,对于生产级代码,您不应该强制解包,除非您知道一个值会在那里。此外,对于 HTTP 请求,您会希望它们在解包数据之前成功 - 请参阅 dataTask 的其他参数。 -
贾斯汀,我已经添加了基于您的 cmets 的精炼代码。请看上面。我仍然在同一个位置意外地发现零。想法?
标签: json swift api swiftui get