【问题标题】:How to show data from Api inside my SwiftUI app如何在我的 SwiftUI 应用程序中显示来自 Api 的数据
【发布时间】:2021-09-28 04:29:20
【问题描述】:

我正在制作这个应用程序,它会显示有关即将上映的动漫的某些信息,我为此使用 jikan API,它不需要任何身份验证或任何密钥

这是 API 的外观 -

{
  "request_hash": "request:top:3506eaba6445f7ad5cc2f78417bf6ed916b6aaad",
  "request_cached": true,
  "request_cache_expiry": 43675,
  "top": [
    {
      "mal_id": 40356,
      "rank": 1,
      "title": "Tate no Yuusha no Nariagari Season 2",
      "url": "https://myanimelist.net/anime/40356/Tate_no_Yuusha_no_Nariagari_Season_2",
      "image_url": "https://cdn.myanimelist.net/images/anime/1245/111800.jpg?s=7302aaeb3bc4e1433b32d094e9d6f6f0",
      "type": "TV",
      "episodes": {},
      "start_date": "Apr 2022",
      "end_date": {},
      "members": 300837,
      "score": 0
    },
    {
      "mal_id": 48583,
      "rank": 2,
      "title": "Shingeki no Kyojin: The Final Season Part 2",
      "url": "https://myanimelist.net/anime/48583/Shingeki_no_Kyojin__The_Final_Season_Part_2",
      "image_url": "https://cdn.myanimelist.net/images/anime/1989/116577.jpg?s=f6312bda2e67f86595936d0264696a91",
      "type": "TV",
      "episodes": {},
      "start_date": "Jan 2022",
      "end_date": {},
      "members": 253849,
      "score": 0
    },

这就是我编写代码的方式,由于某种原因,当我运行应用程序时,我只是得到一个纯空白的白屏,并且它还打印出我添加的最后一个打印语句,上面写着“Fetch Failed: Unknown error” 请帮我解决这个问题

 import SwiftUI


struct Response: Codable{
    var top: [Result]
    
}

struct Result: Codable {
    
    var mal_id: Int
    var rank: Int
    var title: String
    var type: String
    var start_date: String
    
}

struct ContentView: View {
    
    func loadData() {

        guard let url = URL(string: "https://api.jikan.moe/v3/top/anime/1/upcoming") else {
            print("Invalid URL")
            return
        }
        
        let request = URLRequest(url: url)
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
                    // we have good data – go back to the main thread
                    DispatchQueue.main.async {
                        // update our UI
                        self.top = decodedResponse.top
                    }

                    // everything is good, so we can exit
                    return
                }
            }

            // if we're still here it means there was a problem
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
        }.resume()
    }
    
    @State private var top = [Result]()
    var body: some View {
        ScrollView {
            List(top, id: \.mal_id) { item in
                        VStack(alignment: .leading) {
                            Text(item.title)
                                .font(.headline)
                            Text(String("\(item.rank)"))
                                .font(.headline)
                            Text(item.type)
                                .font(.headline)
                            Text(item.start_date)
                                .font(.headline)
                            
                        }
                    }
                       }
           
        .onAppear(perform: loadData)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

【问题讨论】:

  • 不要try? 。您忽略了一个可能的且非常具有描述性的错误。在catch 子句中将try? 替换为trydo - catch 块和print(error)
  • 感谢您的帮助,现在已经解决了,当我按照您告诉我的操作时,它抛出了一个错误提示。 " 从抛出函数类型 '(Data?, URLResponse?, Error?) throws -> Void' 到非抛出函数类型 '(Data?, URLResponse?, Error?) -> Void' 的无效转换”
  • 所以我只是选择了另一个解决方案,现在它可以工作了
  • 正如我所说你必须写do { let decodedResponse = try .... } catch { print(error) }

标签: json api swiftui


【解决方案1】:

首先,解码数据时遇到问题,看起来有些字段是null,所以你应该将它们解码为可选,在这种情况下我发现var start_date: String字段是导致问题的一个,所以请确保将其设为可选:var start_date: String?

其次,您不需要将List 放在ScrollView 中,因为默认情况下ListScrollView 的一种类型。

型号:(使某些文件可选)

struct Result: Codable {
    var mal_id: Int
    var rank: Int
    var title: String
    var type: String
    var start_date: String?
}

正文内容:(移除了滚动视图)

var body: some View {
    List(top, id: \.mal_id) { item in
        VStack(alignment: .leading) {
            Text(item.title)
                .font(.headline)
            Text(String("\(item.rank)"))
                .font(.headline)
            Text(item.type)
                .font(.headline)
            Text(item.start_date ?? "")
                .font(.headline)
            
        }
    }
    .onAppear(perform: loadData)
}

【讨论】:

  • 非常感谢,它现在可以工作了,我还有最后一个问题,尽管我也想包含图像,因为当我将该属性作为字符串添加到我的结构中以及何时添加图像 URL 时我在我的视图中使用 Image(item.image_url) 它说在资产文件夹中找不到图像,如何解决这个问题!?
  • 那是因为Image 视图可以方便地加载您在本地已经拥有的图像(例如在您的资产文件夹中)
  • 在从远程URL加载图片时,有多种方法可以实现,当然可以轻松加载iOS 15(stackoverflow.com/questions/60677622/…)中的图片
  • 但是如果你想运行低版本(iOS 15之前),你可能需要依赖其他解决方案,我推荐(hackingwithswift.com/forums/swiftui/loading-images/3292)但是网上有很多不同的解决方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 2023-01-25
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多