Swift使用API请求添加数组



我试图创建从API收集的数据列表,我卡住了如何将API结果附加到列表。我知道这有点蠢,但我希望有人能看看代码,帮我解决如何实现它

内部有虚拟数据的函数:

private func getLocations() -> [Crime] {
let locationArray : [Crime] = [
Crime(latitude: 51.4586, longitude: -2.5936),
Crime(latitude: 51.4599, longitude: -2.5939)
]
return locationArray
}
我的API调用函数:
struct Crime: Codable, Identifiable{
var id = UUID()
var latitude: Double
var longitude: Double
}
func getAPI(completion: u/escaping ([Crime])->()){
guard let crimeURL = URL(string: "https://data.police.uk/api/crimes-street/drugs?poly=51.5623,-2.5709:51.4952,-2.7292:51.4008,-2.6235:51.4028,-2.4875:51.4569,-2.4274&date=2022-02") else {return}
URLSession.shared.dataTask(with: crimeURL) { (data, _, _) in
let crime = try! JSONDecoder().decode([Crime].self, from: data!)
DispatchQueue.main.async{
completion(crime)
}
}
.resume()
}

总而言之,我试图从JSON文件中的每个条目中提取经度和纬度,并以这种格式将其附加到locationArrayCrime(latitude: 51.4586, longitude: -2.5936)

我对swift比较陌生,所以任何关于如何解决这个问题的建议都是欢迎的!

编辑:

作为基础,这是我对它的实现的尝试,但是它不起作用:(

func getLocations() -> [Crime] {
var locationArray : [Crime] = []
getCrimes{ (crimes) in
self.crimes = crimes
}
ForEach(crimes, id: .self) crime in{
locationArray.append(Crime(latitude:crimes.latitude, longitude: crimes.longitude))
}
return locationArray
}

编辑2:

在玩了一会儿之后,我似乎偶然发现了一个"半解决方案"。下图:

func getLocations() -> [Crime] {
var locationArray : [Crime] = []
getCrimes{ (crimes) in
self.crimes = crimes
}
for crime in crimes{
locationArray.append(Crime(latitude:crime.latitude, longitude: crime.longitude))
}
return locationArray
}

但我确实收到这个错误当试图运行模拟器:Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "id", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))

所以如果有人知道如何解决这个问题,请让我知道!

你应该添加一个do-catch块来包装try!

func getAPI(completion: u/escaping ([Crime])->()){
guard let crimeURL = URL(string: "https://data.police.uk/api/crimes-street/drugs?poly=51.5623,-2.5709:51.4952,-2.7292:51.4008,-2.6235:51.4028,-2.4875:51.4569,-2.4274&date=2022-02") else {return}
URLSession.shared.dataTask(with: crimeURL) { (data, _, _) in
do {
let crime = try! JSONDecoder().decode([Crime].self, from: data!)
DispatchQueue.main.async{
completion(crime)
}  
} catch {
print(error.localizedDescription)
}

}
.resume()
}

问题可能是因为犯罪模型与数据不匹配,尝试将id类型更改为Int:

struct Crime: Codable, Identifiable{
var id: Int
var latitude: Double
var longitude: Double
}

问题是您没有为您的Crime结构提供正确的格式。

如果你看一下你的JSON,它看起来是这样的:

{
"category": "drugs",
"location_type": "Force",
"location": {
"latitude": "51.461094",
"street": {
"id": 543495,
"name": "On or near King Square Avenue"
},
"longitude": "-2.591658"
},
"context": "",
"outcome_status": {
"category": "Further action is not in the public interest",
"date": "2022-04"
},
"persistent_id": "7fb542fb5265c59ff0b613c473e69af6cf2b9421313c7cef28d626b1360523c5",
"id": 99489374,
"location_subtype": "",
"month": "2022-02"}

纬度和经度值位于位置节点下。只需稍微调整一下代码,就可以开始了:

struct Location: Codable {
let latitude: String
let longitude: String
}
struct Crime: Codable {
let location: Location
let id: Int
enum CodingKeys: String, CodingKey {
case location
case id

}
}
func getAPI(completion: @escaping ([Crime])->()){
guard let crimeURL = URL(string: "https://data.police.uk/api/crimes-street/drugs?poly=51.5623,-2.5709:51.4952,-2.7292:51.4008,-2.6235:51.4028,-2.4875:51.4569,-2.4274&date=2022-02") else {return}
URLSession.shared.dataTask(with: crimeURL) { (data, _, _) in
do {
let crime = try JSONDecoder().decode([Crime].self, from: data!)
completion(crime)
} catch {
print(error)
}

}
.resume()
}

//Call your method and you are good to go.
getAPI { crimes in
print(crimes)
}