无法从可观察对象中提取数据

Posted

技术标签:

【中文标题】无法从可观察对象中提取数据【英文标题】:Unable to extract data from Observable Object 【发布时间】:2020-01-16 23:51:48 【问题描述】:

我正在尝试显示来自观察对象的数据。

最初我试图保持简单,只显示结构的一个成员:'base'(值:“stations”)。

struct Sample: Codable 
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind
    let clouds: Clouds
    let dt: Double
//    let sys: Sys
    let id: Int
    let name: String
//    let cod: Int

我用“?”做了一些防御性编码但我得到以下编译器错误:

所以我替换了'?用'!',知道我应该有一些数据。

我发现这令人沮丧,来自命令式范式背景。 我做错了什么?

这是数据转储:

示例(坐标:DataTaskPubTab.Coord(经度:-0.13,纬度:51.51),天气: [DataTaskPubTab.Weather(id: 300, main: "细雨", description: "光 强度毛毛雨")],基地:“车站”,主要: DataTaskPubTab.Main(温度:280.32,压力:1012,湿度:81, tempMin:279.15,tempMax:281.15),能见度:10000,风: DataTaskPubTab.Wind(速度:4.1,度:80),云: DataTaskPubTab.Clouds(all: 90), dt: 1485789600.0, id: 2643743, name: “伦敦”)

这是 Observable 对象:

class StandardWeatherReportLoader: ObservableObject 
    @Published var networkMessage: String?
    @Published var hasAlert = false
    @Published var weatherReport: Sample?
    @Published var hasReport = false

    func doStandard() 
        let url = EndPoint.weather.path()
        var request = URLRequest(url: EndPoint.weather.path()!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let task = URLSession.shared.dataTask(with: url!)  (data: Data?, _: URLResponse?, error: Error?) -> Void in
            DispatchQueue.main.async 
                guard error == nil else 
                    self.networkMessage = error?.localizedDescription
                    self.hasAlert = true
                    return
                

                do 
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    let result = try decoder.decode(Sample.self, from: data!)
                    self.weatherReport = result
                    self.hasReport = true
                    print(result)
                 catch let error as NSError 
                    print(error)
                
            
        
        task.resume()
    

【问题讨论】:

【参考方案1】:

显然这有效:

struct StandardWeatherView: View 
    @EnvironmentObject var settings: Settings
    @ObservedObject var standardWeatherReportLoader = StandardWeatherReportLoader()

    init() 
        self.standardWeatherReportLoader.doStandard()
    

    var body: some View 
        NavigationView 
            ZStack 
                Color("FernGreen").edgesIgnoringSafeArea(.all)
                VStack 
                    if standardWeatherReportLoader.weatherReport?.base == nil 
                        Text("Sorry, NO data.")
                     else 
                        Text(standardWeatherReportLoader.weatherReport!.base)
                    

                    Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
                
                .navigationBarTitle(Text("Weather Report"), displayMode: .inline)
            .alert(isPresented: $standardWeatherReportLoader.hasAlert, content:  () -> Alert in
                Alert(title: Text(verbatim: standardWeatherReportLoader.networkMessage!))
            )
        
    

【讨论】:

【参考方案2】:

很可能在第一次呈现视图时 Web 服务数据还不可用。所以你不应该用! 强制解开这个值。如果你想在这两种情况下都创建一个Text() 元素,你可以简单地使用?? 操作(参见Swift 语言文档中的Nil-Coalescing Operator):

Text(standardWeatherReportLoader.weatherReport?.base ?? "Sorry, NO data.")

【讨论】:

以上是关于无法从可观察对象中提取数据的主要内容,如果未能解决你的问题,请参考以下文章

从可观察对象返回的复杂对象中访问数据

使用异步管道从可观察对象中读取对象字段

当其他可观察对象为真时,从可观察对象中获取项目

从可观察到的返回数据的角度 forEach 循环(Firebase 驱动)

如何强制视图刷新而不让它从可观察对象自动触发?

Angular 4 - 从可观察到的将新项目推送到数组