【问题标题】:How do I access integer value in JSON API?如何访问 JSON API 中的整数值?
【发布时间】:2021-07-12 12:51:09
【问题描述】:

我正在尝试快速从 JSON 文件中检索整数值。我这样做如下:self.trip.dist = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].dist) 但我收到此错误error

这是我正在访问的JSON file 的链接。我正在尝试访问 dist 值。

这些是我的结构:

struct JSONStructure: Decodable {
    var Trip: [TripStructure]
}
 
struct TripStructure: Decodable {
    var LegList: LegListStructure
}
 
struct LegListStructure: Decodable {
    var Leg: [LegStructure]
}
 
struct LegStructure: Decodable {
    var Origin: StationStructure
    var Destination: StationStructure
    var Product: ProductStructure
    var name: String
    var type: String
    var dist: Int
}
 
struct StationStructure: Decodable {
    var time: String
    var name: String
    var date: String
}
 
struct ProductStructure: Decodable {
    var catIn: String
}
 
 
// Just to condense my varibales
struct LocationInfo {
    var iD = String()
    var input = String()
    var lat = String()
    var lon = String()
    var name = String()
    var time = String()
    var date = String()
    var vehicleType = String()
    var transportType = String()
    var dist = String()
    var legName = String()
}

这是我用来调用函数的函数:

    @Published var trip: LocationInfo = LocationInfo()
    @Published var dest: LocationInfo = LocationInfo()
    @Published var origin: LocationInfo = LocationInfo()
    @Published var arrivalTime = String()
    @Published var travelDate = String()
    @Published var searchForArrival = String()
    @Published var tripIndex = Int()
    @Published var Trips: [Dictionary<String, String>] = []
 
public func FetchTrip() {
        Trips.removeAll()
        
        let tripKey = "40892db48b394d3a86b2439f9f3800fd"
        let tripUrl = URL(string: "http://api.sl.se/api2/TravelplannerV3_1/trip.json?key=\(tripKey)&originExtId=\(self.origin.iD)&destExtId=\(self.dest.iD)&Date=\(self.travelDate)&Time=\(self.arrivalTime)&searchForArrival=\(self.searchForArrival)")
        
        URLSession.shared.dataTask(with: tripUrl!) {data, response, error in
            if let data = data {
                do {
                    let decodedJson = try JSONDecoder().decode(JSONStructure.self, from: data)
                    self.tripIndex = decodedJson.Trip.count - 1
                    
                    for i in 0..<decodedJson.Trip[self.tripIndex].LegList.Leg.count {
                        self.trip.transportType = decodedJson.Trip[self.tripIndex].LegList.Leg[i].type
 
                        if self.trip.transportType == "WALK" {
                            self.origin.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.name
                            self.origin.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.time.prefix(5))
                            self.origin.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.date
 
                            self.dest.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.name
                            self.dest.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.time.prefix(5))
                            self.dest.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.date
                            
                            self.trip.vehicleType = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Product.catIn
                            self.trip.dist = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].dist) // This is where the problem lies
                            
                            self.Trips.append(["Origin": self.origin.name, "Destination": self.dest.name, "OriginTime": self.origin.time, "DestTime": self.dest.time, "OriginDate": self.origin.date, "DestDate": self.dest.date, "TransportType": self.trip.transportType, "VehicleType": self.trip.vehicleType, "Distance": self.trip.dist])
                        }
                        
                        else {
                            self.origin.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.name
                            self.origin.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.time.prefix(5))
                            self.origin.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.date
 
                            self.dest.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.name
                            self.dest.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.time.prefix(5))
                            self.dest.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.date
                            
                            self.trip.vehicleType = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Product.catIn
                            self.trip.legName = decodedJson.Trip[self.tripIndex].LegList.Leg[i].name
                            
                            self.Trips.append(["Origin": self.origin.name, "Destination": self.dest.name, "OriginTime": self.origin.time, "DestTime": self.dest.time, "OriginDate": self.origin.date, "DestDate": self.dest.date, "TransportType": self.trip.transportType, "VehicleType": self.trip.vehicleType, "LegName": self.trip.legName])
                        }
                    }
                } catch {
                    print(error)
                }
            }
        }.resume()
    }

我在控制台中收到此错误: keyNotFound(CodingKeys(stringValue: "dist", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "Trip", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "LegList", intValue: nil), CodingKeys(stringValue: "Leg", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"dist\", intValue: nil) (\"dist\").", underlyingError: nil))

【问题讨论】:

    标签: json swift xcode api


    【解决方案1】:

    这个网站很棒:https://app.quicktype.io您只需粘贴您的 json,它就会为您编写 Codable。 QED。

    您需要使用 Optional Int 来提取 dist 值,因为并非所有腿都有一个。

    这是访问dist 值所需的最低要求:

    func example() {
        let url = URL(string: "https://api.sl.se/api2/TravelplannerV3_1/trip.json?key=40892db48b394d3a86b2439f9f3800fd&originExtId=300101416&destExtId=300101426&Date=2021-04-15&Time=08:00&searchForArrival=1")!
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let data = data {
                let travelplanner = try? JSONDecoder().decode(Travelplanner.self, from: data)
                print(travelplanner as Any)
            }
        }
        .resume()
    }
    
    struct Travelplanner: Codable {
        let trip: [Trip]
    
        enum CodingKeys: String, CodingKey {
            case trip = "Trip"
        }
    }
    
    struct Trip: Codable {
        let legList: LegList
    
        enum CodingKeys: String, CodingKey {
            case legList = "LegList"
        }
    }
    
    struct LegList: Codable {
        let leg: [Leg]
    
        enum CodingKeys: String, CodingKey {
            case leg = "Leg"
        }
    }
    
    struct Leg: Codable {
        let origin: Station
        let destination: Station
        let product: Product?
        let name: String
        let type: String
        let dist: Int?
    
        enum CodingKeys: String, CodingKey {
            case origin = "Origin"
            case destination = "Destination"
            case product = "Product"
            case name
            case type
            case dist
        }
    }
    
    struct Station: Codable {
        let name: String
        let time: String
        let date: String
    }
    
    struct Product: Codable {
        let catIn: String
    }
    

    【讨论】:

    • 感谢您的回答,我实现了您的代码,但在控制台中仍然收到相同的错误。当我的行程不包含WALK 时,它确实有效,但是当它发生相同的错误时,唯一的区别是keyNotFound(CodingKeys(stringValue: "dist", 现在被keyNotFound(CodingKeys(stringValue: "Product" 关闭。
    • 那你一定是在做网络请求本身错了......我将网络请求添加到我的示例代码中。将以上内容粘贴到您的项目中并在您的应用程序委托中调用example()。它起作用。如果你的不起作用,那么找出差异并修复它们。
    • “产品”属性也需要是可选的。并非所有的腿都有产品。
    • 我终于通过添加产品可选解决了这个问题,就像我对 dist 所做的那样。这解决了所有问题,该应用程序现在可以运行。感谢您的帮助。
    【解决方案2】:

    很高兴您找到了解决方案。我认为您的代码还有其他问题需要解决。

    以下代码具有相同的效果,但 IMO 更简洁:

        func fetchTrip() {
            let url = URL(string: "https://api.sl.se/api2/TravelplannerV3_1/trip.json?key=40892db48b394d3a86b2439f9f3800fd&originExtId=300101416&destExtId=300101426&Date=2021-04-15&Time=08:00&searchForArrival=1")!
            URLSession.shared.dataTask(with: url) { (data, response, error) in
                if let data = data {
                    let decodedJson = try! JSONDecoder().decode(Travelplanner.self, from: data)
                    let lastLeg = decodedJson.trip.last?.legList.leg.last
                    self.tripIndex = decodedJson.trip.count - 1
                    self.trip.transportType = lastLeg?.type ?? ""
                    self.origin.name = lastLeg?.origin.name ?? ""
                    self.origin.time = lastLeg.map { String($0.origin.time.prefix(5)) } ?? ""
                    self.origin.date = lastLeg?.origin.date ?? ""
                    self.dest.name = lastLeg?.destination.name ?? ""
                    self.dest.time = lastLeg.map { String($0.destination.time.prefix(5)) } ?? ""
                    self.dest.date = lastLeg?.destination.date ?? ""
                    self.trip.vehicleType = lastLeg?.product?.catIn ?? ""
                    if let lastWalkLeg = decodedJson.trip.last?.legList.leg.last(where: { $0.type == "WALK" }) {
                        self.trip.dist = String(lastWalkLeg.dist ?? 0)
                    }
                    if let lastNonwalkLeg = decodedJson.trip.last?.legList.leg.last(where: { $0.type != "WALK" }) {
                        self.trip.legName = lastNonwalkLeg.name
                    }
    
                    self.trips = (decodedJson.trip.last?.legList.leg ?? [])
                        .map { $0.asDict }
                }
            }
            .resume()
        }
    }
    
    extension Leg {
        var asDict: [String: String] {
            [
                "Origin": origin.name,
                "Destination": destination.name,
                "OriginTime": String(origin.time.prefix(5)),
                "DestTime": String(destination.time.prefix(5)),
                "OriginDate": origin.date,
                "DestDate": destination.date,
                "TransportType": type,
                "VehicleType": product?.catIn ?? "",
            ].merging(type == "WALK" ? ["Distance": String(dist ?? 0)] : ["LegName": name], uniquingKeysWith: { $1 })
        }
    }
    

    对于大多数变量,您每次都通过循环分配给相同的 var。这只是浪费。从循环的最后一个元素中分配值并完成它。

    if...else... 块中完成的大部分工作都是相同的。将相同的部分分开,只将关心Leg.type 的部分放在 if/else 块中。您实际上是在类的其他方法中使用所有类属性,还是只是使用它们以一种奇怪的方式制作局部变量? (我在上面的代码中假设前者以防万一。)如果您不需要在其他方法中需要所有其他属性,唯一的一点是填充trips数组,您可以卸载大部分代码(当然self.trips =... 行除外。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多