首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >API调用过程中Swift valueNotFound的问题

API调用过程中Swift valueNotFound的问题
EN

Stack Overflow用户
提问于 2020-09-22 07:09:14
回答 2查看 982关注 0票数 0

我正在寻找一些帮助与Swift项目工作。我正在构建一个从API中提取航空天气数据的应用程序,这种情况很常见:

用户需要来自机场气象站的数据,目前的报告说:

  • 风力10 kt
  • 散射云2500英尺
  • 能见度10 SM
  • 轻雨

用户需要来自机场气象站的数据,KJAX -当前的报告说:

  • 风力16 kt
  • 风力24 kt
  • 破裂云1400英尺
  • 分散云1900英尺

<代码>H 119少数云2400英尺<代码>H 220<代码>F 221

在这个简单的例子中,您可能会注意到,在本报告所述期间,没有为KJAX提供任何阵风数据,也没有为K民建联指定“特殊天气”(即雨、雾、雾)。我的应用程序需要能够处理“零”或不提供数据,而不只是告诉我有一个valueNotFound或索引超出范围。

下面是API:https://avwx.docs.apiary.io/#reference/0/metar/get-metar-report

这是我的代码:

代码语言:javascript
复制
import Foundation

struct WeatherManager {
    let weatherURL = "https://avwx.rest/api/metar/"

    func fetchWeather (stationICAO: String) {
        let urlString = "\(weatherURL)\(stationICAO)?token=OVi45FiTDo1LmyodShfOfoizNe5m9wyuO6Mkc95AN-c"
        performRequest(urlString: urlString)
    }
    
    func performRequest (urlString: String) {
        if let url = URL(string: urlString) {
            let session = URLSession(configuration: .default)
                
            
            let task = session.dataTask(with: url) { (data, response, error) in
                if error != nil {
                    print(error!)
                    return
                }
                
                if let safeData = data {
                    self.parseJSON(weatherData: safeData)
                }
            }
            
            task.resume()
            print(urlString)
            
            
            }
        }
    
    func parseJSON(weatherData: Data) {
        
        
        do {
            let decoder = JSONDecoder()
            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
            
            
            
            let lowCloudsType = decodedData.clouds[0].type
            let midCloudsType = decodedData.clouds[1].type 
            let highCloudsType = decodedData.clouds[2].type 
            let lowCloudsAlt = decodedData.clouds[0].altitude
            let midCloudsAlt = decodedData.clouds[1].altitude 
            let highCloudsAlt = decodedData.clouds[2].altitude 
            let reportingStationVar = decodedData.station 
            let windGustValue = decodedData.wind_gust.value 
            let windSpeedValue = decodedData.wind_speed.value 
            let windDirectionValue = decodedData.wind_direction.value 
            let visibilityValue = decodedData.visibility.value
            let flightRulesValue = decodedData.flight_rules
            
            let weather = WeatherModel(lowestCloudsType: lowCloudsType, lowestCloudsAlt: lowCloudsAlt, middleCloudsType: midCloudsType, middleCloudsAlt: midCloudsAlt, highestCloudsType: highCloudsType, highestCloudsAlt: highCloudsAlt, reportingStation: reportingStationVar, windGust: windGustValue, windSpeed: windSpeedValue, windDirection: windDirectionValue, visibility: visibilityValue, flightRules: flightRulesValue)
            
            print(weather.flightConditions)
            
        } catch {
            print(error)
        }
    }
    
    

}
代码语言:javascript
复制
import Foundation

struct WeatherModel {
    
    
    let lowestCloudsType: String
    let lowestCloudsAlt: Int
    let middleCloudsType: String
    let middleCloudsAlt: Int
    let highestCloudsType: String
    let highestCloudsAlt: Int
    let reportingStation: String
    let windGust: Int
    let windSpeed: Int
    let windDirection: Int
    let visibility: Int
    let flightRules: String
    
    var flightConditions: String {
        switch flightRules {
        case "VFR":
            return "green"
        case "MVFR":
            return "blue"
        case "IFR":
            return "red"
        case "LIFR":
            return "purple"
        default:
            return "gray"
        
        }
    }
}

最后一个:

代码语言:javascript
复制
import Foundation

struct WeatherData: Decodable {
   
    
    let clouds: [Clouds]
    let flight_rules: String
    let remarks: String
    let wind_speed: WindSpeed
    let wind_gust: WindGust
    let wind_direction: WindDirection
    let visibility: Visibility

    let station: String
}



struct Clouds: Decodable {
    let type: String
    let altitude: Int
}

struct WindSpeed: Decodable {
    let value: Int
}

struct WindGust: Decodable {
    let value: Int
}

struct WindDirection: Decodable {
    let value: Int
}

struct Visibility: Decodable {
    let value: Int
}

根据我所玩的内容,当我进入一个没有所有给定信息的站点时,我会得到以下错误,如果气象服务报告了这些信息,我需要能够向用户展示这些信息。

代码语言:javascript
复制
2020-09-22 02:47:58.930421-0400 AvWx Pro[66612:4483807] libMobileGestalt MobileGestaltCache.c:38: No persisted cache on this platform.
KDAB
https://avwx.rest/api/metar/KDAB?token=(mySecretToken)
2020-09-22 02:48:02.943231-0400 AvWx Pro[66612:4483809] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
valueNotFound(Swift.KeyedDecodingContainer<AvWx_Pro.WindGust.(unknown context at $1053fb3b8).CodingKeys>, 
Swift.DecodingError.Context(codingPath: 
[CodingKeys(stringValue: "wind_gust", intValue: nil)], 
debugDescription: "Cannot get keyed decoding container 
-- found null value instead.", underlyingError: nil))

当我使用一个没有报告所有三个可能的云层的机场时,会出现另一个错误:

代码语言:javascript
复制
2020-09-22 03:06:02.398628-0400 AvWx Pro[66736:4497432] libMobileGestalt MobileGestaltCache.c:38: No persisted cache on this platform.
KJAX
https://avwx.rest/api/metar/KJAX?token=(mySecretKey)
2020-09-22 03:06:07.955064-0400 AvWx Pro[66736:4497429] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Fatal error: Index out of range: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1200.2.22.2/swift/stdlib/public/core/ContiguousArrayBuffer.swift, line 444
2020-09-22 03:06:08.908826-0400 AvWx Pro[66736:4497429] Fatal error: Index out of range: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1200.2.22.2/swift/stdlib/public/core/ContiguousArrayBuffer.swift, line 444
(lldb) 

我花了几个小时来尝试我在网上找到的各种解决方案,包括使用选项和强制展开,使用守护let,使用if let,以及一些其他的解决方案。我现在很迷茫。

我是新的这个平台(作为海报),并将真正感谢任何洞察力任何人都可以提供!谢谢你提前帮忙。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-22 09:35:57

为了在解码json时避免崩溃,您应该对结构进行正确的配置,并在访问值之前检查字段:

  1. 可选字段

CodingKeys(stringValue:"wind_gust",intValue: nil),debugDescription:“无法得到键控解码容器--找到空值。”,underlyingError: nil) wind_gust可以是空的,因此应该使其成为可选的:

如果一个字段在响应中可以是空的或空的,那么应该使它在您的结构中是可选的,例如:

代码语言:javascript
复制
struct WeatherData: Decodable { 
    ...
    let wind_gust: WindGust?
    ...
}

然后,在代码中,如果存在wind_gust,只需使用可选绑定提取值:

代码语言:javascript
复制
    if let value = decodedData.wind_gust?.value {
        print(value)
    }

  1. Arrays

致命错误:超出范围的索引

在访问项之前,必须始终检查数组的边界,例如:

代码语言:javascript
复制
let clouds = decodedData.clouds
let lowCloudsType = clouds.count > 0 ? clouds[0].type : nil
let midCloudsType = clouds.count > 1 ? clouds[1].type : nil
let highCloudsType = clouds.count > 2 ? clouds[2].type : nil

if let low = lowCloudsType, let mid = midCloudsType, let high = highCloudsType {
    print(low)
    print(mid)
    print(high)
}
票数 0
EN

Stack Overflow用户

发布于 2020-09-22 09:06:57

答案是使用选项

考虑下面的操场示例,年龄和位置属性是可选的,JSON中缺少location属性。

代码语言:javascript
复制
import Foundation

struct TestModel: Decodable {

    let name: String
    let age: Int?
    let location: String?

    enum CodingKeys: String, CodingKey {
            case name
            case age
            case location
    }
}

let jsonData = """
{
    "name": "John Smith",
    "age": 28
}
""".data(using: .utf8)!

let result = try JSONDecoder().decode(TestModel.self, from: jsonData)
print(result)

输出

TestModel(姓名:"John“,年龄:可选(28),地点:0)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64004687

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档