SwiftUI - 无法呈现 jsonData

Posted

技术标签:

【中文标题】SwiftUI - 无法呈现 jsonData【英文标题】:SwiftUI - Not able to render the jsonData 【发布时间】:2020-05-05 06:33:55 【问题描述】:

我对 SwiftUi 非常陌生,我正在尝试查看 json 数据,我目前正在从 openweathermap.org 检索天气数据,这是一个用于检索当前天气的免费 API。我收到解析天气 Json 消息时出错。我不确定我做错了什么!任何帮助将不胜感激,我已经坚持了一天。我参考了许多关于如何使用 Published var 和 ObservableObject 的博客和教程,但我无法解决这个问题。

This is my swift file


struct WeatherData 
    public var Id: Int
    public var main: String
    public var weather: [Weather]
    public var icon: String


extension WeatherData: Decodable, Identifiable 
    var id: Int return Id



struct WeatherView: View 
    @ObservedObject var fetch = FetchWeather()

    var body: some View 
        VStack 
            List(fetch.weatherData) 
                wthr in
                VStack(alignment: .leading)
                    Text("\(wthr.id)")
                    Text("\(wthr.weather[0].description)")
                    Text("\(wthr.icon)")
                        .font(.system(size:11))
                        .foregroundColor(Color.gray)
                
            
        
    


struct Weather: Decodable 
    let description: String


struct WeatherView_Previews: PreviewProvider 
    static var previews: some View 
        WeatherView()
    



class FetchWeather: ObservableObject 
    @Published var weatherData = [WeatherData] ()

    init() 
        load()
    

    func load() 
        let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=London&appid=myapikey")!


        URLSession.shared.dataTask(with: url) 
            (data, response, error) in
            do 
                if let wthData = data 
                    let decodedData = try JSONDecoder().decode([WeatherData].self, from: wthData)
                    DispatchQueue.main.sync 
                        self.weatherData = decodedData
                    
                
                else 
                    print("No json Data available")
                
            catch 
                print("Error parsing Weather Json")
            
        .resume()
    

【问题讨论】:

很可能你的结构是错误的,但你没有打印相关的错误,而是一些硬编码的字符串,这真的很糟糕。将 catch 中的 print 语句更改为 print(error)。然后你可以谷歌或在 *** 上搜索更多信息,因为这个 api 似乎很受欢迎。 *** search 阅读 JSON。根对象显然不是一个数组。并且永远不要在主线程上.sync 你遇到了什么错误? @jawadAli 错误很明显:Expected array but found dictionary @JoakimDanielson 非常感谢您的回复。我更改为错误并收到此消息: typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", 基础错误:无)) 【参考方案1】:

试试这个代码。我已注册获取 api 并相应地更正了模型、视图模型和视图。我还没有为图标字符串添加图像加载器。

import SwiftUI

struct Weather: Decodable
    var description: String
    var icon :String


struct MainData: Decodable 
    var temp: Double
    var pressure: Int
    var humidity: Int
    var temp_min: Double
    var temp_max: Double



struct WeatherData: Decodable, Identifiable 
    var id: Int
    var main: MainData
    var weather: [Weather]
    var name: String


struct WeatherView: View 
    @ObservedObject var fetch = FetchWeather()

    var body: some View 
        VStack(alignment: .leading) 
            Text("Current Weather").font(.title).padding()
            List(fetch.weatherData)  wthr in
                HStack 
                    VStack(alignment: .leading)
                        Text("\(wthr.name)")
                        Text("\(wthr.weather[0].description)")
                            .font(.system(size:11))
                            .foregroundColor(Color.gray)
                    
                    Spacer()
                    VStack(alignment: .trailing)
                        Text("\(wthr.main.temp-273.15, specifier: "%.1f") ºC")
                    
                    Text("\(wthr.weather[0].icon)") // Image from "https://openweathermap.org/img/w/\(wthr.weather[0].icon).png"
                        .foregroundColor(Color.gray)
                
            
        
    


class FetchWeather: ObservableObject 
    @Published var weatherData = [WeatherData]()

    private let baseURL = "https://api.openweathermap.org/data/2.5/weather?q="
    private let cities = [ "London", "Mumbai", "New+york", "Vatican+City" ]
    private let api = "&appid="+"e44ebeb18c332fff46ab956bb38f9e07"

    init() 
        for city in self.cities 
            self.load(self.baseURL+city+self.api)
        
    

    func load(_ urlString: String) 
        if let url = URL(string: urlString) 
            URLSession.shared.dataTask(with: url)  (data, response, error) in
                do 
                    if let wthData = data 
                        let decodedData = try JSONDecoder().decode(WeatherData.self, from: wthData)
                        DispatchQueue.main.sync 
                            self.weatherData.append(decodedData)
                        
                    
                    else 
                        print("No json Data available")
                    
                 catch let error as NSError
                    print(error.localizedDescription)
                
            .resume()
         else 
            print("Unable to decode URL")
        
    

【讨论】:

@amithrampur 代码中的api是有限使用的。使用您自己的 API。此外,如果这有效,请接受答案。干杯! 是的,这段代码很好,我会努力改进我的应用程序。非常感谢您回来查看 我确实有一个问题。如果我不想为城市设置值,我想直接从用户那里读取它怎么办。 @AmithRampur 在实际用例场景中,如果用户提供一些数据,则需要将其存储在 CoreData 或 Google Firebase 等永久存储中。对于核心数据集成,请查看github.com/nikhiljohn10/CoreData-MacOS。 我希望通过文本从用户那里获取输入,并在不同的视图中使用相同的输入。例如,上面天气 api 结构中的名称可以说有一个文本框供用户输入城市名称,用户输入圣何塞,我想根据用户输入的输入检索天气。我想知道我怎么能做到这一点。任何的意见都将会有帮助。我不想存储在永久存储中

以上是关于SwiftUI - 无法呈现 jsonData的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中呈现视图控制器

我无法获取用户的 AWS Cognito 凭证 (swiftUI)

在 Xcode 11、SwiftUI 中呈现 UIViewController 的问题

从 SwiftUI 视图呈现 UIActivityViewController

在 SwiftUI 中从 UIViewRepresentable 呈现视图

如何使用 SwiftUI 呈现警报