swift cannot dig into JSONDecoder data got via alamofire - json

Cannot read data from section "weather" of JSONDecoder file, got via Almofire
the data printed in console:
{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":521,"main":"Rain","description":"shower
rain","icon":"09d"}],"base":"stations","main":{"temp":289.64,"pressure":1006,"humidity":48,"temp_min":286.48,"temp_max":292.59},"visibility":10000,"wind":{"speed":1},"clouds":{"all":85},"dt":1558190870,"sys":{"type":1,"id":1414,"message":0.009,"country":"GB","sunrise":1558152298,"sunset":1558208948},"id":2643743,"name":"London","cod":200}
struct MyWeatherData: Codable {
let coord : coord
let weather : weather
}
struct coord: Codable {
let lon: Double
let lat: Double
}
struct weather: Codable {
let array : [unknown] //here is my problem
let base : String
}
struct unknown : Codable {
let id : Int
let main: String
let description : String
let icon : String
}
let cityLink = "https://api.openweathermap.org/data/2.5/weather?q=London"
Alamofire.request(self.cityLink+"&APPID=\(self.myId)").responseJSON { (response) in
// print("Request: \(String(describing: response.request))") // original url request
// print("Response: \(String(describing: response.response))")
// print("Result: \(response.result)")
if let data = response.data, let utf8 = String(data: data, encoding: .utf8) {
print("Data is: \(utf8)")
do {
let myData = try JSONDecoder().decode(MyWeatherData.self, from: data)
// print("lat is: \(myData.coord.lat)") //ok, working
print("weather is: \(myData.weather.main)") //not working
} catch let myError {
print("error is: ", myError)
}
}
}

No, the problem is not here is my problem, the problem is in MyWeatherData.
Please read the JSON. It's very easy. The value for key weather is wrapped in [] so the object is an array.
And name all structs with uppercase letters to avoid confusion like let weather : weather
struct MyWeatherData : Decodable {
let coord : Coord
let weather : [Weather]
}
struct Coord : Decodable {
let lon: Double
let lat: Double
}
struct Weather : Decodable {
let id : Int
let main: String
let description : String
let icon : String
}

Please name your class/Models with first letter Capitalized.
The problem is that weather is an Array on MyWeatherData so it becomes:
struct MyWeatherData: Codable {
let coord : Coord
let weather : [Weather]
}
struct Coord: Codable {
let lon: Double
let lat: Double
}
struct Weather: Codable {
let id : Int
let main: String
let description : String
let icon : String
}

In MyWeatherData the weather property should have [weather] type, as the JSON returns an array in weather key:
{
"coord": {
"lon": -0.13,
"lat": 51.51
},
"weather": [{
"id": 521,
"main": "Rain",
"description": "shower rain",
"icon": "09d"
}],
"base": "stations",
"main": {
"temp": 289.64,
"pressure": 1006,
"humidity": 48,
"temp_min": 286.48,
"temp_max": 292.59
},
"visibility": 10000,
"wind": {
"speed": 1
},
"clouds": {
"all": 85
},
"dt": 1558190870,
"sys": {
"type": 1,
"id": 1414,
"message": 0.009,
"country": "GB",
"sunrise": 1558152298,
"sunset": 1558208948
},
"id": 2643743,
"name": "London",
"cod": 200
}
So your types should look like this:
struct MyWeatherData: Codable {
let coord: coord
let weather: [weather]
let base: String
}
struct coord: Codable {
let lon: Double
let lat: Double
}
struct weather : Codable {
let id : Int
let main: String
let description : String
let icon : String
}
And then you can get weather instance by myWeatherData.weather.first

Related

JSONDecoder returning nil while parsing

I have the following function:
func executeGet( completion: #escaping (Data?, Error?) -> Void) {
AF.request("https:URL",
method:.get,
headers:headers).response{ response in
debugPrint(response)
if let error = response.error {
completion(nil, error)
}
else if let jsonArray = response.value as? Data{
completion(jsonArray, nil)
}
}
}
Which is being called as follows:
executeGet() { (json, error) in
if let error = error{
print(error.localizedDescription)
}
else if let json = json {
print(type(of:json))
print(json)
let welcome = try? JSONDecoder().decode(Welcome.self, from: json)
print(welcome)
}
}
But for some reason, my 'welcome' value always returns nil. Can anyone suggest what could've gone wrong? When I print(json) I'm getting '294 Bytes' for some reason so clearly something went wrong before decoding, right?
EDIT: Upon Udi's request here's the Welcome struct
// MARK: - Welcome
struct Welcome: Codable {
let statusCode: Int
let messageCode: String
let result: Result
}
// MARK: - Result
struct Result: Codable {
let id: String
let inputParameters: InputParameters
let robotID: String
let runByUserID, runByTaskMonitorID: JSONNull?
let runByAPI: Bool
let createdAt, startedAt, finishedAt: Int
let userFriendlyError: JSONNull?
let triedRecordingVideo: Bool
let videoURL: String
let videoRemovedAt: Int
let retriedOriginalTaskID: String
let retriedByTaskID: JSONNull?
let capturedDataTemporaryURL: String
let capturedTexts: CapturedTexts
let capturedScreenshots: CapturedScreenshots
let capturedLists: CapturedLists
enum CodingKeys: String, CodingKey {
case id, inputParameters
case robotID = "robotId"
case runByUserID = "runByUserId"
case runByTaskMonitorID = "runByTaskMonitorId"
case runByAPI, createdAt, startedAt, finishedAt, userFriendlyError, triedRecordingVideo
case videoURL = "videoUrl"
case videoRemovedAt
case retriedOriginalTaskID = "retriedOriginalTaskId"
case retriedByTaskID = "retriedByTaskId"
case capturedDataTemporaryURL = "capturedDataTemporaryUrl"
case capturedTexts, capturedScreenshots, capturedLists
}
}
// MARK: - CapturedLists
struct CapturedLists: Codable {
let companies: [Company]
}
// MARK: - Company
struct Company: Codable {
let position, name, location, description: String
enum CodingKeys: String, CodingKey {
case position = "Position"
case name, location, description
}
}
// MARK: - CapturedScreenshots
struct CapturedScreenshots: Codable {
}
// MARK: - CapturedTexts
struct CapturedTexts: Codable {
let productName, width, patternRepeat, construction: String
let fiber: String
let color: JSONNull?
let mainImage: String
enum CodingKeys: String, CodingKey {
case productName = "Product Name"
case width = "Width"
case patternRepeat = "Pattern Repeat"
case construction = "Construction"
case fiber = "Fiber"
case color = "Color"
case mainImage = "Main Image"
}
}
// MARK: - InputParameters
struct InputParameters: Codable {
let originURL: String
let companiesSkip, companiesLimit: Int
enum CodingKeys: String, CodingKey {
case originURL = "originUrl"
case companiesSkip = "companies_skip"
case companiesLimit = "companies_limit"
}
}
// MARK: - Encode/decode helpers
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool
{
return true
}
public var hashValue: Int {
return 0
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
and here's a sample of JSON response
{
"statusCode": 200,
"messageCode": "success",
"result": {
"id": "f6fb62b6-f06a-4bf7-a623-c6a35c2e70b0",
"inputParameters": {
"originUrl": "https://www.ycombinator.com/companies/airbnb",
"companies_skip": 0,
"companies_limit": 10
},
"robotId": "4f5cd7ff-6c98-4cac-8cf0-d7d0cb050b06",
"runByUserId": null,
"runByTaskMonitorId": null,
"runByAPI": true,
"createdAt": 1620739118,
"startedAt": 1620739118,
"finishedAt": 1620739118,
"userFriendlyError": null,
"triedRecordingVideo": true,
"videoUrl": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/system-1620230966-b1a9688b-05d3-4682-beeb-9ce035e482b1.mp4",
"videoRemovedAt": 1620739118,
"retriedOriginalTaskId": "673da019-bf0c-476e-9c4f-d35252a151dc",
"retriedByTaskId": null,
"capturedDataTemporaryUrl": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/system-1620230966-b1a9688b-05d3-4682-beeb-9ce035e482b1.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQVG3TPBVXHSCAX63%2F20221031%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221031T185642Z&X-Amz-Expires=1800&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEJP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJIMEYCIQDfX8VNAl5kBgttrCU85U5wc1ZtSOmshO6%2FPilXOv8nvgIhAIveFfsk%2B2CnEkrMZWriodEPsj0osO5a5zV6eVu%2FXfuZKp8DCHwQAhoMMDQ1NTU3NzA4OTA3IgyrbhVK0MP1WMFBXh0q%2FAJulP5qfaV5mn3NRbINqZN4hy4Dg3IujNrZjw8ef32sWE1Gj2D%2Fc0YTJUzvx%2Fnm7LxyNO6AR35mrVy%2FBm9Q80UIspkcLMl45EK%2FoUDO0fAvoUF8g6iZ905qS3MvnOTxXkObhM1PVmpFeJFMw3jksnOPfKE4X7Ut%2FJXNwD%2F5QzdkQCXkGem%2BlrYSSSf8jB8lihTAjT%2FNXmOKMv3jktmZ13T8J1R8F8zeuLPMQf7QphUzlKn5joPb28cConluQC97y%2BjwxqIYjvIFKXY9cZEoaHGh4c6FbXsia714zG3CQp8NSGLbqCCu93oJI1Z61E%2BZ6PhB3vZGdBvXi61AlJcxZ7sti6i0h4VAbWspiJIgWwoZzrsTtneBNNpUW9tvtacGgEZIwAKV%2F3AhVEZu3WC1eQ9HtfjT9%2FjW99SEB8VVGXwkM%2FA9mtT%2FuiL0cAfQZRMhtbQJXXDRdkYEw%2FWuhjJ3zxEtEB2m3uH%2B%2BUEzOzGTd5Knm%2Bero%2BhMfN8X%2Botm3DDbtICbBjqcAf5Riii0XE1w2TZvpm%2FPNHTchCu7FnNz5hfvflv8scpgO5M4bGpy%2FadI4%2F7AUQqCQXFw4scF0FCCdb8AKJZsFGG18W1jjDHyR0YuxZFQ%2FJQRt0JP3yr%2BkVxjAH7qTtc0AzF%2FnGTgy3MOF%2Bm6Y7EkyCWyV2r6o1JTBQMftlf7MI8Uvw4cSZE6JoZviaFtmKVLGGgR4F3cDiyU56augA%3D%3D&X-Amz-Signature=a7bb4d7597ad37cdf1f260890c3c474f7f49334db58c9650d75302a34126f7bc&X-Amz-SignedHeaders=host",
"capturedTexts": {
"Product Name": "Alexis",
"Width": "15",
"Pattern Repeat": "PATTERN REPEAT",
"Construction": "Hand woven",
"Fiber": "100% Wool",
"Color": null,
"Main Image": "https://isteam.wsimg.com/ip/e31f7bba-252b-4669-9209-639d1c00765d/ols/258_original"
},
"capturedScreenshots": {
"top-ads": {
"id": "b4d132f3-12d9-4770-ac7d-88e481fc5b47",
"name": "Top ads",
"src": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/00001-user-1620230947-6f113cf2-90ef-4c66-a448-9d5c6bd64873.png",
"width": 600,
"height": 120,
"x": 201,
"y": 142,
"deviceScaleFactor": 1.2,
"full": "page",
"comparedToScreenshotId": "29d742c2-6f45-4f29-9d48-ba6fe66e6e3d",
"diffImageSrc": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/00001-user-1620230947-6f113cf2-90ef-4c66-a448-9d5c6bd64873.png",
"changePercentage": 20,
"diffThreshold": 5,
"fileRemovedAt": 1620739118
}
},
"capturedLists": {
"companies": [
{
"Position": "1",
"name": "Airbnb",
"location": "San Francisco, CA, USA",
"description": "Book accommodations around the world."
},
{
"Position": "2",
"name": "Coin base",
"location": "San Francisco, CA, USA",
"description": "Buy, sell, and manage crypto currencies."
},
{
"Position": "3",
"name": "DoorDash",
"location": "San Francisco, CA, USA",
"description": "Restaurant delivery."
}
]
}
}
}
EDIT2: Upon Rob's suggestion, I tried do-try-catch, as follows:
executeGet() { (json, error) in
if let error = error{
print(error.localizedDescription)
}
else if let json = json {
print(type(of:json)) // Data
print(json) // 2479 Bytes
do{
var welcome = try JSONDecoder().decode(Welcome.self, from: json)
print(welcome)
}
catch {
print(error)
}
}
}
Which reports the error:
keyNotFound(CodingKeys(stringValue: "companies_skip", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), CodingKeys(stringValue: "inputParameters", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: "companies_skip", intValue: nil) ("companies_skip").", underlyingError: nil))
The string response you show in your comment, means you get a valid response from the server,
and so you should be able to decode it with the following models.
Use #vadian answer to your previous question :
Unable to parse JSON data properly from Alomafire
Here are the test code and models to decode the response into a set of structs.
Note you will have to consult the server doc to determine which properties are Optional and adjust the code (i,e put ?)
where nessesary .
struct ContentView: View {
#State var welcome: WelcomeResponse?
var body: some View {
VStack {
if let response = welcome {
Text(response.messageCode)
Text("\(response.statusCode)")
ForEach(response.result.capturedLists.companies) { item in
Text(item.description)
}
}
}
.onAppear {
let json = """
{
"statusCode": 200,
"messageCode": "success",
"result": {
"id": "f6fb62b6-f06a-4bf7-a623-c6a35c2e70b0",
"inputParameters": {
"originUrl": "https://www.ycombinator.com/companies/airbnb",
"companies_skip": 0,
"companies_limit": 10
},
"robotId": "4f5cd7ff-6c98-4cac-8cf0-d7d0cb050b06",
"runByUserId": null,
"runByTaskMonitorId": null,
"runByAPI": true,
"createdAt": 1620739118,
"startedAt": 1620739118,
"finishedAt": 1620739118,
"userFriendlyError": null,
"triedRecordingVideo": true,
"videoUrl": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/system-1620230966-b1a9688b-05d3-4682-beeb-9ce035e482b1.mp4",
"videoRemovedAt": 1620739118,
"retriedOriginalTaskId": "673da019-bf0c-476e-9c4f-d35252a151dc",
"retriedByTaskId": null,
"capturedDataTemporaryUrl": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/system-1620230966-b1a9688b-05d3-4682-beeb-9ce035e482b1.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQVG3TPBVXHSCAX63%2F20221031%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221031T185642Z&X-Amz-Expires=1800&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEJP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJIMEYCIQDfX8VNAl5kBgttrCU85U5wc1ZtSOmshO6%2FPilXOv8nvgIhAIveFfsk%2B2CnEkrMZWriodEPsj0osO5a5zV6eVu%2FXfuZKp8DCHwQAhoMMDQ1NTU3NzA4OTA3IgyrbhVK0MP1WMFBXh0q%2FAJulP5qfaV5mn3NRbINqZN4hy4Dg3IujNrZjw8ef32sWE1Gj2D%2Fc0YTJUzvx%2Fnm7LxyNO6AR35mrVy%2FBm9Q80UIspkcLMl45EK%2FoUDO0fAvoUF8g6iZ905qS3MvnOTxXkObhM1PVmpFeJFMw3jksnOPfKE4X7Ut%2FJXNwD%2F5QzdkQCXkGem%2BlrYSSSf8jB8lihTAjT%2FNXmOKMv3jktmZ13T8J1R8F8zeuLPMQf7QphUzlKn5joPb28cConluQC97y%2BjwxqIYjvIFKXY9cZEoaHGh4c6FbXsia714zG3CQp8NSGLbqCCu93oJI1Z61E%2BZ6PhB3vZGdBvXi61AlJcxZ7sti6i0h4VAbWspiJIgWwoZzrsTtneBNNpUW9tvtacGgEZIwAKV%2F3AhVEZu3WC1eQ9HtfjT9%2FjW99SEB8VVGXwkM%2FA9mtT%2FuiL0cAfQZRMhtbQJXXDRdkYEw%2FWuhjJ3zxEtEB2m3uH%2B%2BUEzOzGTd5Knm%2Bero%2BhMfN8X%2Botm3DDbtICbBjqcAf5Riii0XE1w2TZvpm%2FPNHTchCu7FnNz5hfvflv8scpgO5M4bGpy%2FadI4%2F7AUQqCQXFw4scF0FCCdb8AKJZsFGG18W1jjDHyR0YuxZFQ%2FJQRt0JP3yr%2BkVxjAH7qTtc0AzF%2FnGTgy3MOF%2Bm6Y7EkyCWyV2r6o1JTBQMftlf7MI8Uvw4cSZE6JoZviaFtmKVLGGgR4F3cDiyU56augA%3D%3D&X-Amz-Signature=a7bb4d7597ad37cdf1f260890c3c474f7f49334db58c9650d75302a34126f7bc&X-Amz-SignedHeaders=host",
"capturedTexts": {
"Product Name": "Alexis",
"Width": "15",
"Pattern Repeat": "PATTERN REPEAT",
"Construction": "Hand woven",
"Fiber": "100% Wool",
"Color": null,
"Main Image": "https://isteam.wsimg.com/ip/e31f7bba-252b-4669-9209-639d1c00765d/ols/258_original"
},
"capturedScreenshots": {
"top-ads": {
"id": "b4d132f3-12d9-4770-ac7d-88e481fc5b47",
"name": "Top ads",
"src": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/00001-user-1620230947-6f113cf2-90ef-4c66-a448-9d5c6bd64873.png",
"width": 600,
"height": 120,
"x": 201,
"y": 142,
"deviceScaleFactor": 1.2,
"full": "page",
"comparedToScreenshotId": "29d742c2-6f45-4f29-9d48-ba6fe66e6e3d",
"diffImageSrc": "https://prod-browseai-captured-data.s3.amazonaws.com/1fae674a-2788-46a8-83c8-95c4664c6d25/6326b3c1-7b16-4256-a323-7d8d8954bd4e/1061671f-7f71-42ac-bb9a-207d126d1f3a/00001-user-1620230947-6f113cf2-90ef-4c66-a448-9d5c6bd64873.png",
"changePercentage": 20,
"diffThreshold": 5,
"fileRemovedAt": 1620739118
}
},
"capturedLists": {
"companies": [
{
"Position": "1",
"name": "Airbnb",
"location": "San Francisco, CA, USA",
"description": "Book accommodations around the world."
},
{
"Position": "2",
"name": "Coin base",
"location": "San Francisco, CA, USA",
"description": "Buy, sell, and manage crypto currencies."
},
{
"Position": "3",
"name": "DoorDash",
"location": "San Francisco, CA, USA",
"description": "Restaurant delivery."
}
]
}
}
}
"""
// simulated API data from the server
let data = json.data(using: .utf8)!
do {
let results = try JSONDecoder().decode(WelcomeResponse.self, from: data)
welcome = results
print("\n---> results: \(results) \n")
} catch {
print("\n---> decoding error: \n \(error)\n")
}
}
}
}
// MARK: - WelcomeResponse
struct WelcomeResponse: Codable {
let statusCode: Int
let messageCode: String
let result: Result
}
// MARK: - Result
struct Result: Codable {
let id: String
let inputParameters: InputParameters
let robotID: String
let runByUserID, runByTaskMonitorID: String?
let runByAPI: Bool
let createdAt, startedAt, finishedAt: Int
let userFriendlyError: String?
let triedRecordingVideo: Bool
let videoURL: String
let videoRemovedAt: Int
let retriedOriginalTaskID: String
let retriedByTaskID: String?
let capturedDataTemporaryURL: String
let capturedTexts: CapturedTexts
let capturedScreenshots: CapturedScreenshots
let capturedLists: CapturedLists
enum CodingKeys: String, CodingKey {
case id, inputParameters
case robotID = "robotId"
case runByUserID = "runByUserId"
case runByTaskMonitorID = "runByTaskMonitorId"
case runByAPI, createdAt, startedAt, finishedAt, userFriendlyError, triedRecordingVideo
case videoURL = "videoUrl"
case videoRemovedAt
case retriedOriginalTaskID = "retriedOriginalTaskId"
case retriedByTaskID = "retriedByTaskId"
case capturedDataTemporaryURL = "capturedDataTemporaryUrl"
case capturedTexts, capturedScreenshots, capturedLists
}
}
// MARK: - CapturedLists
struct CapturedLists: Codable {
let companies: [Company]
}
// MARK: - Company
struct Company: Identifiable, Codable {
let id = UUID()
let position, name, location, description: String
enum CodingKeys: String, CodingKey {
case position = "Position"
case name, location, description
}
}
// MARK: - CapturedScreenshots
struct CapturedScreenshots: Codable {
let topAds: TopAds
enum CodingKeys: String, CodingKey {
case topAds = "top-ads"
}
}
// MARK: - TopAds
struct TopAds: Codable {
let id, name: String
let src: String
let width, height, x, y: Int
let deviceScaleFactor: Double
let full, comparedToScreenshotId: String
let diffImageSrc: String
let changePercentage, diffThreshold, fileRemovedAt: Int
}
// MARK: - CapturedTexts
struct CapturedTexts: Codable {
let productName, width, patternRepeat, construction: String
let fiber: String
let color: String?
let mainImage: String
enum CodingKeys: String, CodingKey {
case productName = "Product Name"
case width = "Width"
case patternRepeat = "Pattern Repeat"
case construction = "Construction"
case fiber = "Fiber"
case color = "Color"
case mainImage = "Main Image"
}
}
// MARK: - InputParameters
struct InputParameters: Codable {
let originUrl: String
let companiesSkip: Int?
let companiesLimit: Int?
enum CodingKeys: String, CodingKey {
case originUrl
case companiesSkip = "companies_skip"
case companiesLimit = "companies_limit"
}
}
Your error was reportedly:
keyNotFound(CodingKeys(stringValue: "companies_skip", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), CodingKeys(stringValue: "inputParameters", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: "companies_skip", intValue: nil) ("companies_skip").", underlyingError: nil))
That points you precisely to where the decoding failed. There is apparently no key called companies_skip in result » inputParameters. Now, you don't show us the full response you actually received, so it is hard to be precise. But we can infer from this error that the response does not precisely match your sample JSON, but rather, the companies_skip key is not present.
We might infer from the name, inputParameters, that your request URL (which, again, you have not shared with us) may possibly need to supply that parameter. Or, alternatively, perhaps that parameter name shouldn't be marked as a required sub key of the inputParameters structure (e.g., you might want to make it an optional).
Regardless of the particulars, this is the process. If decoding fails, look at the complete error object, and it will tell you where it had problems. Note, if there are multiple decoding problems, the error will only report the first one, so do not be surprised if it takes a few times and different queries to resolve all of the issues. The first time you start decoding a particular request, resolving all of the potential discrepancies may be an iterative process.

How to get JSON response from URL with json inside in swift

Hi my url of request is:
http://MYDOMAIN/jsonrpc?request=
{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "filter": {"field": "playcount", "operator": "is", "value": "0"}, "limits": { "start" : 0, "end": 75 }, "properties" : ["art", "rating", "thumbnail", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}
How can I parse result in swift?
Use Codable to parse JSON. Try with your demo input.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let someString = """
{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "filter": {"field": "playcount", "operator": "is", "value": "0"}, "limits": { "start" : 0, "end": 75 }, "properties" : ["art", "rating", "thumbnail", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}
"""
let data = someString.data(using: .utf8)!
do{
let jsonDataModels = try JSONDecoder().decode(JSONDataModel.self, from: data)
print(String(data: data, encoding: .utf8)!)
print("jsonDataModels: \(jsonDataModels)")
}catch {
print(error)
}
}
}
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let jSONDataModel = try? newJSONDecoder().decode(JSONDataModel.self, from: jsonData)
import Foundation
// MARK: - JSONDataModel
struct JSONDataModel: Codable {
let jsonrpc, method: String
let params: Params
let id: String
}
// MARK: - Params
struct Params: Codable {
let filter: Filter
let limits: Limits
let properties: [String]
let sort: Sort
}
// MARK: - Filter
struct Filter: Codable {
let field, filterOperator, value: String
enum CodingKeys: String, CodingKey {
case field
case filterOperator = "operator"
case value
}
}
// MARK: - Limits
struct Limits: Codable {
let start, end: Int
}
// MARK: - Sort
struct Sort: Codable {
let order, method: String
let ignorearticle: Bool
}
Another example tries with API call.
import UIKit
import Foundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
do{
let jsonDataModels = try JSONDecoder().decode([JSONDataModel].self, from: data)
print(String(data: data, encoding: .utf8)!)
print("jsonDataModels: \(jsonDataModels)")
}catch{}
}
task.resume()
}
}
struct JSONDataModel: Codable {
let id: Int
let name, username, email: String
let address: Address
let phone, website: String
let company: Company
}
struct Address: Codable {
let street, suite, city, zipcode: String
let geo: Geo
}
struct Geo: Codable {
let lat, lng: String
}
struct Company: Codable {
let name, catchPhrase, bs: String
}

Swift FAILURE: type Mismatch(Swift.Array<Any>)

Is there anyone can help me fix my model? It seems it does not match with the JSON from API Response.
JSON response from postman
{
"error_code": 0,
"data": [
{
"kode": "001",
"name": "BANK INDONESIA PUSAT JAKARTA"
},
{
"kode": "002",
"name": "PT. BANK RAKYAT INDONESIA (Persero) Tbk."
},
{
"kode": "003",
"name": "BANK EKSPOR INDONESIA"
}
],
"msg": "OK"
}
Last Model Edited:
struct ObjectBank: Codable {
let errorCode: Int
let data: [Bank]
let msg: String
enum CodingKeys : String, CodingKey {
case errorCode = "error_code" , data , msg
}
}
struct Bank: Codable {
let kode: String
let name: String
}
Still got error like this
Store model using alamofire
private static func performRequest<T:Decodable>(route:APIRouter,
decoder: JSONDecoder = JSONDecoder(), completion:#escaping
(Result<T>)->Void) -> DataRequest {
// Alamofire.request(route).responseJSON {
// response in
// print(response)
// }
return Alamofire.request(route).responseJSONDecodable (decoder:
decoder){ (response: DataResponse<T>) in
//print(response)
completion(response.result)
}
}
data is an array not dictionary
let data:[Bank]
//
struct ObjectBank: Codable {
let errorCode: Int
let data: [Bank]
let msg: String
enum CodingKeys : String, CodingKey {
case errorCode = "error_code" , data , msg
}
}
struct Bank: Codable {
let kode: String
let name: String
}
//
do {
let dic = try JSONDecoder().decode(ObjectBank.self,data)
}
catch {
print(error)
}
The structure of your response is ok in principle which you can see using the following Playground:
import Cocoa
let jsonData = """
{
"error_code": 0,
"data": [
{
"kode": "001",
"name": "BANK INDONESIA PUSAT JAKARTA"
},
{
"kode": "002",
"name": "PT. BANK RAKYAT INDONESIA (Persero) Tbk."
},
{
"kode": "003",
"name": "BANK EKSPOR INDONESIA"
}
],
"msg": "OK"
}
""".data(using: .utf8)!
struct ObjectBank: Codable {
let errorCode: Int
let data: [Bank]
let msg: String
enum CodingKeys : String, CodingKey {
case errorCode = "error_code" , data , msg
}
}
struct Bank: Codable {
let kode: String
let name: String
}
do {
let banks = try JSONDecoder().decode(ObjectBank.self, from: jsonData)
print(banks)
} catch {
print(error)
}
This will parse without error. Since I do not know AlamoFire very well I have to assume that there is something going wrong with the type of your completion closure. It will "somehow" have to guess that you want to parse ObjectBank in order to make any sense of your response.
Maybe you would have an easier time with responseData?

Creating a list from Nested JSON using Decodable in Swift 4

I have been able to convert JSON to structs using Swift 4's Decodable, unfortunately i have been unable to do so with a JSON key called "list" , which is a list ([]) that contains other structs.
{
"cod":"200",
"message":0.0061,
"cnt":5,
"list":[
{
"dt":1522605600,
"main":{ },
"weather":[ ],
"clouds":{ },
"wind":{ },
"rain":{ },
"sys":{ },
"dt_txt":"2018-04-01 18:00:00"
},
{
"dt":1522616400,
"main":{ },
"weather":[ ],
"clouds":{ },
"wind":{ },
"rain":{ },
"sys":{ },
"dt_txt":"2018-04-01 21:00:00"
},
{
"dt":1522627200,
"main":{
"temp":277.21,
"temp_min":277.21,
"temp_max":277.506,
"pressure":1016.3,
"sea_level":1023.98,
"grnd_level":1016.3,
"humidity":84,
"temp_kf":-0.3
},
These are my structs, my approach was to make ForecastInstance the overall container which holds a property "list" (like the JSON) that is of type ForecastList (which holds the nested structs).
struct ForecastInstance : Decodable {
let list: [ForecastList]?
}
struct ForecastList : Decodable {
let dt : Int?
let weather : [Weather]?
let main : Main?
let wind : Wind?
}
struct Wind : Decodable {
let speed: Float
}
struct Coord : Decodable {
let lon : Float
let lat : Float
}
struct Main : Decodable{
let temp : Double
let pressure : Int
let humidity : Int
let temp_min: Double
let temp_max: Double
}
struct Weather : Decodable{
let id : Int
let main: String
let description: String
let icon: String
}
When i do the following in the view controller , it fails.
self.currentForecast = try
JSONDecoder().decode(ForecastInstance.self,from:data!)
Any help will be greatly appreciated.
This was my error
debugDescription: "Parsed JSON number <1017.42> does not fit in Int.", underlyingError: nil))
Changing the property pressure of type Int to float did the trick.
It works in Playground!
Here is a nice article about Codable:
Swift 4 Decodable: Beyond The Basics.
I hope it will be helpful.
let weatherJSON = """
{
"list": [{
"dt": 1522605600,
"main": {
"temp": 30,
"humidity": 50,
"pressure": 40
},
"weather": ["cloudly"],
"clouds": {},
"wind": {},
"rain": {},
"sys": {},
"dt_txt": "2018-04-01 18:00:00"
}]
}
""".data(using: .utf8)!
struct Main: Codable {
let temp: Int?
let humidity: Int?
let pressure: Int?
}
struct Weather: Codable {
let dt: Int?
let main: Main?
let weather: [String]?
}
struct WeatherList: Codable {
let list: [Weather]?
}
let weather = try JSONDecoder().decode(WeatherList.self, from: weatherJSON)
let count = "\(weather.list?.count ?? 0)"
print(count)
Your top level struct needs to look like this to mimic your JSON structure. The rest of your structs look fine if you are still getting errors I suggest you relook at those structs as well.
struct ForecastInstance : Decodable {
let cod: String?
let message: Int?
let cnt: Int?
let list: [ForecastList]?
}

JSON parsing in Swift 4 with complex & nested data

I am currently trying to make a weather app using JSON from https://openweathermap.org but I am having trouble with the weather part in the JSON file. I am not sure how to access the 'id' value inside the object.
{
"base": "stations",
"clouds": {
"all": 36
},
"cod": 200,
"coord": {
"lat": 51.51,
"lon":
-0.13
},
"dt": 1507497600,
"id": 2643743,
"main": {
"humidity": 82,
"pressure": 1021,
"temp": 10.65,
"temp_max": 13,
"temp_min": 9
},
"name": "London",
"sys": {
"country": "GB",
"id": 5091,
"message": 0.0036,
"sunrise": 1507443264,
"sunset": 1507483213,
"type": 1
},
"visibility": 10000,
"weather": [{
"description": "scattered clouds",
"icon": "03n",
"id": 802,
"main": "Clouds"
}],
"wind": {
"deg": 200,
"speed": 1.5
}
}
How would I be able to get the data in there. In my swift code, I am using structures that conform to the new 'codable' protocol in swift 4.
// all structures for the data
struct CurrentLocalWeather: Codable {
let base: String
let clouds: clouds
let cod: Int
let coord: coord
let dt: Int
let id: Int
let main: main
let name: String
let sys: sys
let visibility: Int
let weather: [weather]
let wind: wind
}
struct clouds: Codable {
let all: Int
}
struct coord: Codable {
let lat: Double
let lon: Double
}
struct main: Codable {
let humidity: Double
let pressure: Double
let temp: Double
let temp_max: Double
let temp_min: Double
}
struct sys: Codable {
let country: String
let id: Int
let message: Double
let sunrise: Double
let sunset: Double
let type: Int
}
struct weather: Codable {
let description: String
let icon: String
let id: Int
let main: String
}
struct wind: Codable {
let deg: Double
let speed: Double
}
// Get data from weather server
func getCurrentWeatherData() {
let jsonUrlString = "https://api.openweathermap.org/data/2.5/weather?id=2643743&units=metric&APPID=fdf04e9483817ae2fa77048f7e6705e8"
guard let url = URL(string: jsonUrlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let json = try decoder.decode(CurrentLocalWeather.self, from: data)
print("Data Successfully Retrieved!\nServer Response: \(json.cod)\nLocation: \(json.name)")
DispatchQueue.main.async() {
// Any of the following allows me to access the data from the JSON
self.locationLabel.text = "\(json.name)"
self.temperatureLabel.text = "Currently: \(json.main.temp)ºC"
self.highTemperatureLabel.text = "High: \(json.main.temp_max)ºC"
self.lowTemperatureLabel.text = "Low: \(json.main.temp_min)ºC"
self.sunriseLabel.text = "\(self.convertFromUnixToNormal(time: json.sys.sunrise))"
self.sunsetLabel.text = "\(self.convertFromUnixToNormal(time: json.sys.sunset))"
self.humidityLabel.text = "Humidity: \(json.main.humidity)%"
self.pressureLabel.text = "Pressure: \(json.main.pressure) hPa"
self.windSpeedLabel.text = "Wind Speed: \(json.wind.speed) km/h"
}
} catch let jsonErr {
print("Error: \(jsonErr)")
}
}.resume()
}
You need to properly identify your json string and provide all necessary structures to decode it. Just by looking at the json provided you can have an idea of the necessary structs to decode it properly:
struct CurrentLocalWeather: Codable {
let base: String
let clouds: Clouds
let cod: Int
let coord: Coord
let dt: Int
let id: Int
let main: Main
let name: String
let sys: Sys
let visibility: Int
let weather: [Weather]
let wind: Wind
}
struct Clouds: Codable {
let all: Int
}
struct Coord: Codable {
let lat: Double
let lon: Double
}
struct Main: Codable {
let humidity: Int
let pressure: Int
let temp: Double
let tempMax: Int
let tempMin: Int
private enum CodingKeys: String, CodingKey {
case humidity, pressure, temp, tempMax = "temp_max", tempMin = "temp_min"
}
}
struct Sys: Codable {
let country: String
let id: Int
let message: Double
let sunrise: UInt64
let sunset: UInt64
let type: Int
}
struct Weather: Codable {
let description: String
let icon: String
let id: Int
let main: String
}
struct Wind: Codable {
let deg: Int
let speed: Double
}
let weatherData = Data("""
{"base" : "stations",
"clouds": { "all": 36 },
"cod" : 200,
"coord" : { "lat": 51.51,
"lon": -0.13},
"dt": 1507497600,
"id": 2643743,
"main": {
"humidity": 82,
"pressure": 1021,
"temp": 10.65,
"temp_max": 13,
"temp_min": 9},
"name": "London",
"sys": {
"country": "GB",
"id": 5091,
"message": 0.0036,
"sunrise": 1507443264,
"sunset": 1507483213,
"type": 1 },
"visibility": 10000,
"weather": [{
"description": "scattered clouds",
"icon": "03n",
"id": 802,
"main": "Clouds"}],
"wind": {
"deg": 200,
"speed": 1.5
}
}
""".utf8)
let decoder = JSONDecoder()
do {
let currentLocalWeather = try decoder.decode(CurrentLocalWeather.self, from: weatherData)
print(currentLocalWeather) // "CurrentLocalWeather(base: "stations", clouds: __lldb_expr_367.Clouds(all: 36), cod: 200, coord: __lldb_expr_367.Coord(lat: 51.509999999999998, lon: -0.13), dt: 1507497600, id: 2643743, main: __lldb_expr_367.Main(humidity: 82, pressure: 1021, temp: 10.65, temp_max: 13, temp_min: 9), name: "London", sys: __lldb_expr_367.Sys(country: "GB", id: 5091, message: 0.0035999999999999999, sunrise: 1507443264, sunset: 1507483213, type: 1), visibility: 10000, weather: [__lldb_expr_367.Weather(description: "scattered clouds", icon: "03n", id: 802, main: "Clouds")], wind: __lldb_expr_367.Wind(deg: 200, speed: 1.5))\n"
} catch {
print(error)
}
You need to define types for the custom types in your JSON, e.g. weather, clouds, coord, etc. I would recommend looking at the example in the documentation.
In the example, the Landmark type has a 'location' property which is of Coordinate type. You could even use the Coordinate type in the example for the coord property in your JSON object. However, you will need to provide the correct keys using the CodingKey protocol which is also described in the documentation. For example, your Coordinate type may look like this:
struct Coordinate: Codable {
var latitude: Double
var longitude: Double
enum CodingKeys: String, CodingKey {
case latitude = "lat"
case longitude = "lon"
}
}