如何在Swift中解析数组API?

时间:2019-11-13 14:45:39

标签: arrays swift api

我尝试从看起来像this的API中获取信息:

我可以使用以下方法解析信息:

override func viewDidLoad() {
    super.viewDidLoad()
    getAPI()
}

func getAPI() {
    let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
        if error == nil {
            guard let urlContent = data else { return }

            do {
                let JSONResult = try JSONSerialization.jsonObject(with: urlContent, options: .mutableContainers)
                print("JSON Result:", JSONResult)

                print("-----------------")
                print(type(of: JSONResult))

            } catch {
                print("JSON processing failed.")
            }
        } else {
            print("Error serializing JSON:", error!)
        }
    }
    task.resume()
}

但是我在从API检索单个数据时遇到麻烦(例如“ x”,“ y”和“ companyZoneId”)。我尝试从JSONResult(JSONResult.first)中提取第一个元素,但是它仅显示数组中第一个元素的组成部分(因此,我假设我在array(?)中有一个数组。

如何获取和存储这些元素?因为那样的话我想在地图上显示这些位置,但这是我以后要处理的另一步。目前,我一直坚持从该API数组的每个元素中检索单个信息,而我会根据您的专业知识为我提供指导。

我在这里阅读了不同的教程,并在youtube上看到了一些视频,但没有一个能帮助我解决这种特殊情况。

感谢您的帮助。

问候!

3 个答案:

答案 0 :(得分:0)

找到了我的答案: 首先,我创建了一个包含所有API元素的结构:

dfb

然后,我创建了一种方法来从API中获取所需的元素:

struct MyInfo: Codable {
let id: String
let name: String
let x: Double // Longitude
let y: Double // Latitude
let licencePlate: String?
let range: Int?
let batteryLevel: Int?
let seats: Int?
let model: String?
let resourceImageId: String?
let pricePerMinuteParking: Int?
let pricePerMinuteDriving: Int?
let realTimeData: Bool?
let engineType: String?
let resourceType: String?
let companyZoneId: Int
let helmets: Int?
let station: Bool?
let availableResources: Int?
let spacesAvailable: Int?
let allowDropoff: Bool?
let bikesAvailable: Int?
}

现在,我还有一个无法解决的问题:我无法将x和y值(来自jsonResult)分配给类内部的全局变量(self.lonX和self.latY)。

我该如何实现?我做了另一个应用程序,在该应用程序中我做了类似的事情(创建了一个全局变量结构,我分配了从API获取的值以供其他地方使用),但现在看来它不起作用。

我在寻找您的经验和提示。

感谢您的帮助。

答案 1 :(得分:0)

我建议您使用quicktype。只需将您的json粘贴在那里,它将为您生成模型对象以对其进行解码。这就是使用json所得到的:

// MARK: - WelcomeElement
class WelcomeElement: Codable {
    let id, name: String
    let x, y: Double
    let licencePlate: String?
    let range, batteryLevel, seats: Int?
    let model: Model?
    let resourceImageID: ResourceImageID?
    let pricePerMinuteParking, pricePerMinuteDriving: Int?
    let realTimeData: Bool
    let engineType: String?
    let resourceType: ResourceType?
    let companyZoneID: Int
    let helmets: Int?
    let station: Bool?
    let availableResources, spacesAvailable: Int?
    let allowDropoff: Bool?
    let bikesAvailable: Int?

    enum CodingKeys: String, CodingKey {
        case id, name, x, y, licencePlate, range, batteryLevel, seats, model
        case resourceImageID = "resourceImageId"
        case pricePerMinuteParking, pricePerMinuteDriving, realTimeData, engineType, resourceType
        case companyZoneID = "companyZoneId"
        case helmets, station, availableResources, spacesAvailable, allowDropoff, bikesAvailable
    }

    init(id: String, name: String, x: Double, y: Double, licencePlate: String?, range: Int?, batteryLevel: Int?, seats: Int?, model: Model?, resourceImageID: ResourceImageID?, pricePerMinuteParking: Int?, pricePerMinuteDriving: Int?, realTimeData: Bool, engineType: String?, resourceType: ResourceType?, companyZoneID: Int, helmets: Int?, station: Bool?, availableResources: Int?, spacesAvailable: Int?, allowDropoff: Bool?, bikesAvailable: Int?) {
        self.id = id
        self.name = name
        self.x = x
        self.y = y
        self.licencePlate = licencePlate
        self.range = range
        self.batteryLevel = batteryLevel
        self.seats = seats
        self.model = model
        self.resourceImageID = resourceImageID
        self.pricePerMinuteParking = pricePerMinuteParking
        self.pricePerMinuteDriving = pricePerMinuteDriving
        self.realTimeData = realTimeData
        self.engineType = engineType
        self.resourceType = resourceType
        self.companyZoneID = companyZoneID
        self.helmets = helmets
        self.station = station
        self.availableResources = availableResources
        self.spacesAvailable = spacesAvailable
        self.allowDropoff = allowDropoff
        self.bikesAvailable = bikesAvailable
    }
}

enum Model: String, Codable {
    case askoll = "Askoll"
    case bmw1Series = "BMW 1 Series"
    case bmwX1 = "BMW X1"
    case citroenCZero = "Citroen C-Zero"
    case mini3Door = "MINI 3-Door"
    case miniConvertible = "MINI Convertible"
}

enum ResourceImageID: String, Codable {
    case vehicleGenDN = "vehicle_gen_dn"
    case vehicleGenDNBmwS1 = "vehicle_gen_dn_bmw_s1"
    case vehicleGenEcooltra = "vehicle_gen_ecooltra"
    case vehicleGenEmov = "vehicle_gen_emov"
}

enum ResourceType: String, Codable {
    case car = "CAR"
    case electricCar = "ELECTRIC_CAR"
    case moped = "MOPED"
}

typealias Welcome = [WelcomeElement]

然后只使用JSONDecoder

let welcome = try? newJSONDecoder().decode(Welcome.self, from: jsonData)

答案 2 :(得分:0)

您使用结构完成此操作的方式很棒。您还可以通过使用与JSON相同的结构强制转换结果来获取值({}是字典,[]是数组)

例如,如果您的结果返回为:

{"Food": [
         "category": "Meat",
         "safeTimeLeftOut": "2 Hours"
       ],
       [
         "category": "Dairy",
         "safeTimeLeftOut: "3 Hours"
       ]
}

这是[String:Any]类型的结果,需要这样转换。

let result = JSONResult as? [String:Any]

现在您可以将结果转换为适当的类型

let jsonDict = result["Food"] as? [[[String:String]]] //Array of Array of Dictionaries with key/value String

foodDict将为:[[[[“ category”:“肉”],[“ safeTimeLeftOut”:“ 2小时”]]],[[“ category”:“乳制品”],[“ safeTimeLeftOut:” 3小时“ ]]]

然后您可以遍历它以获得每本字典

for arrOfDicts in jsonDict {
    print(arrOfDicts) //prints the whole array of dictionaries
    for foodDict in arrOfDicts {
        print(foodDict) //prints 1 JSON array
        //if you want a value:
        if let category = foodDict["category"] {
            print(category) //prints the value of the key "category"
        }
    }
}