Parse nested data from JSON using Codable - json

I am trying to parse nested data from JSON response but not getting success. Below is what i tried so far and the json response trying to parse.
// JSON
{
"statusCode": 200,
"success": true,
"data": {
"tDetail": [
{
"roleId": null,
"id": 34,
"userId": 126,
"catId": null,
"importId": null,
"name": "My task from postman",
"myday": 1,
"important": 0,
"completed": 0,
"dateCreated": "2020-02-10T09:05:04.000Z",
"dateModified": "2020-02-10T09:05:04.000Z"
}
],
"steps": [],
"files": [],
}
}
// Struct
struct MyDayAndTaskDetails: Codable
{
let data : [MyTaskDetail]
}
struct MyTaskDetail : Codable {
let roleId, taskId, userId, catId, important, completed, recurring, myday : Int?
let repeatType, name, duedate, reminder, frequency, weekdays, notes, baseurl : String?
let steps : [Steps]
let files : [Files]
private enum CodingKeys: String, CodingKey {
case taskId = "id"
case userId = "userId"
case roleId = "roleId"
case catId = "catId"
case myday = "myday"
case name = "name"
case notes = "notes"
case duedate = "duedate"
case reminder = "reminder"
case recurring = "recurring"
case repeatType = "repeatType"
case important = "important"
case completed = "completed"
case frequency = "frequency"
case weekdays = "weekdays"
case baseurl = "baseurl"
case steps = "Steps"
case files = "Files"
}
}
struct Steps : Codable {
let stepName : String?
let status, stepId : Int?
private enum CodingKeys: String, CodingKey {
case stepName = "stepName"
case status = "status"
case stepId = "stepId"
}
}
struct Files : Codable {
let fileName : String?
private enum CodingKeys: String, CodingKey {
case fileName = "fileName"
}
}

You missed one level
struct MyDayAndTaskDetails: Codable {
let data : Detail
}
struct Detail: Codable {
let tDetail: [MyTaskDetail]
let steps : [Steps]
let files : [Files]
}
and so on

Use this structs, below structs are sufficient for given json. If you have more keys in your json then you can add them into their respective structs.
struct MyDayAndTaskDetails : Codable {
let data : Task?
let statusCode : Int?
let success : Bool?
}
struct Task : Codable {
let files : [Files]?
let steps : [Steps]?
let tDetail : [TDetail]?
}
struct TDetail : Codable {
let catId : String?
let completed : Int?
let dateCreated : String?
let dateModified : String?
let id : Int?
let importId : String?
let important : Int?
let myday : Int?
let name : String?
let roleId : String?
let userId : Int?
}
struct Steps : Codable {
let stepName : String?
let status: Int?
let stepId : Int?
}
struct Files : Codable {
let fileName : String?
}
And decode data with
let decoder = JSONDecoder()
let response = try decoder.decode(MyDayAndTaskDetails.self, from: data)

Related

Issue parsing JSON not in array format

Essentially I would like to take the following JSON and use the data within my project.
To parse the data I need to create a structure - in the past I used this for arrays:
Structure:
struct ArrayStruct: Codable {
let info1: String
let info2: String
}
Array:
[
{
"info1": "Information",
"info2": "More"
}
]
What would the structure for the following data look like?
{
"error": false,
"response": "",
"message": "",
"general": {
"customer": "Customer1",
"code": "CO1234",
"name": "Machine Name",
"category": "machine"
},
"details": {
"taken": "July 15th 2020",
"created": "November 2nd 2020",
"packed": "",
"delivered": ""
}
}
I made a structure using struct with codeable for the data you gave
struct MainResponse : Codable {
let details : Detail?
let error : Bool?
let general : General?
let message : String?
let response : String?
// coding keys not required for this as the data keys are same but added just as an example
enum CodingKeys: String, CodingKey {
case details = "details"
case error = "error"
case general = "general"
case message = "message"
case response = "response"
}
}
struct Detail : Codable {
let created : String?
let delivered : String?
let packed : String?
let taken : String?
}
struct General : Codable {
let category : String?
let code : String?
let customer : String?
let name : String?
}
First You need to create your data Struct like this
struct MainResponse : Codable {
let error : Bool?
let response : String?
let message : String?
let general : General?
let details : Details?
}
Make your General Struct like this
struct General : Codable {
let customer : String?
let code : String?
let name : String?
let category : String?
}
Make your Detail Struct like this
struct Details : Codable {
let taken : String?
let created : String?
let packed : String?
let delivered : String?
}
its easy to create structures now days, there are various tools available, just input the response you will get the data structure, used the following to generate the structure
quicktype.io
// MARK: - Customer
struct Customer: Codable {
let error: Bool?
let response, message: String?
let general: General?
let details: Details?
}
// MARK: - Details
struct Details: Codable {
let taken, created, packed, delivered: String?
}
// MARK: - General
struct General: Codable {
let customer, code, name, category: String?
}

Attempt at utilizing decodable

I am trying to create decodable structs for the JSON that I am receiving, but I keep getting:
keyNotFound(CodingKeys(stringValue: "inquiry_quantity", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "orders", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys...
This is the JSON that I am running through my decoder:
{
"orders_important": 2,
"orders_inquiry": 2,
"orders": [
{
"information": {
"total_price": 12.0,
"order_stage": "CONFIRMED",
"total_cases": 333,
"scanned": false,
"inquiry": false,
"foodhub": "shdw.fh1#agg.com",
"identifier": "GPO00024",
"delivery_date": "2019-11-04"
},
"details": {
"pack_size": "40#",
"cases": 333,
"plu_code": 12434,
"crop_plan": 1633,
"commodity": "Conventional Bananas, , 40#"
}
},
{
"information": {
"inquiree": "FARMER",
"total_price": 23.5,
"order_stage": "INQUIRY",
"inquiry_quantity": 0,
"total_cases": 56,
"scanned": false,
"inquiry": true,
"foodhub": "shdw.fh1#agg.com",
"inquiry_type": "PRICE",
"identifier": "GPO00027",
"inquiry_price": 26.5,
"delivery_date": "2019-11-05",
"inquiry_details": "You have requested $26.5 per case, instead of $23.5."
},
"details": {
"pack_size": "40#",
"cases": 12,
"plu_code": 12434,
"crop_plan": 1589,
"commodity": "Conventional Bananas, , 40#"
}
},
],
"orders_count": 4
}
My decodable structs: (EDIT: Removed Init)
struct OrderBundle: Decodable{
let orders_important : Int
let orders_inquiry:Int
let orders_count: Int
let orders: [Order]
}
struct Order: Decodable {
let inquiry_quantity : Int
let inquiry_price : Int
let inquiry_info : String
let price : Int
let cropPlan : Int
let identifier: String
let deliveryDate : String
let quantity : Int
let unit : String
let status : String
let destination : String
let commodity: String
}
And lastly calling my decoder:
let orderData = try
JSONDecoder().decode(OrderBundle.self, from: data!)
print(orderData)
I have tried it with and without the Init in my Orders and both ways I am still getting the same error.
The main issue is that any dictionary must be decoded to an extra struct if init(from decoder is not provided. So basically the structure of the model must be
struct OrderBundle: Decodable {
struct Information : Decodable {
struct Details : Decodable {
The complete structs are as follows, many struct members must be declared as optional and inquiryPrice is Double, not Int. convertFromSnakeCase converts the snaked_cased keys to camelCased struct members.
struct OrderBundle : Decodable{
let ordersImportant : Int
let ordersInquiry : Int
let ordersCount : Int
let orders : [Order]
}
struct Order : Decodable {
let information : Information
let details : Details
struct Information : Decodable {
let inquiryQuantity : Int?
let inquiryPrice : Double?
let inquiryInfo : String?
let price : Int?
let cropPlan : Int?
let identifier : String
let deliveryDate : String
let quantity : Int?
let unit : String?
let status : String?
let destination : String?
let commodity: String?
}
struct Details : Decodable {
let packSize : String
let cases : Int
let pluCode : Int
let cropPlan : Int
let commodity : String
}
}
And the code to decode it
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let orderData = try decoder.decode(OrderBundle.self, from: data!)
print(orderData)

Swift parsing json read as nil

So i try to parse with jsondecoder and when i see in the log menu, all the data in json is nil. While the json i check in postman all have data on it
so here's the json i want to parse (*i just want to parse the row) :
{
" user": {
"command": "SELECT",
"rowCount": 1,
"oid": null,
"rows": [
{
"user_id": 193,
"u_name": "Gunawan Wibisono",
"email": "gunwibi89#gmail.com",
"div_name": "Design Aplication & Infrastructure",
"url": "2"
}
],
"fields": [
{
"name": "user_id",
"tableID": 1656774,
"columnID": 1,
"dataTypeID": 23,
"dataTypeSize": 4,
"dataTypeModifier": -1,
"format": "text"
},
{
"name": "u_name",
"tableID": 1656774,
"columnID": 2,
"dataTypeID": 1043,
"dataTypeSize": -1,
"dataTypeModifier": 54,
"format": "text"
},
{
"name": "email",
"tableID": 1656774,
"columnID": 3,
"dataTypeID": 1043,
"dataTypeSize": -1,
"dataTypeModifier": 259,
"format": "text"
},
{
"name": "div_name",
"tableID": 1656724,
"columnID": 2,
"dataTypeID": 1043,
"dataTypeSize": -1,
"dataTypeModifier": 259,
"format": "text"
},
{
"name": "url",
"tableID": 1656774,
"columnID": 9,
"dataTypeID": 1043,
"dataTypeSize": -1,
"dataTypeModifier": 259,
"format": "text"
}
],
"_parsers": [
null,
null,
null,
null,
null
],
"_types": {
"_types": {
"arrayParser": {}
},
"text": {},
"binary": {}
},
"RowCtor": null,
"rowAsArray": false
},
"status": 1
}
this is the code :
struct User : Codable {
let command : String?
let rowCount : Int?
let oid : Int?
let rows : [Rowss]?
}
struct Rowss : Codable {
let user_id: Int?
let u_name : String?
let email : String?
let div_name: String?
let url : String?
enum Codingkeys : String, CodingKey {
case user_id = "user_id"
case u_name = "u_name"
case email = "email"
case div_name = "div_name"
case url = "url"
}
}
func Json() {
let user = UserName.text
let pass = Password.text
let json = "http://ratings.immobispsa.com/getslogs/\(user!)/\(pass!)"
guard let myUrl = URL(string: json) else { return }
URLSession.shared.dataTask(with: myUrl) { (data, response, error) in
guard let data = data else {return}
do{
let user = try JSONDecoder().decode(User.self, from: data)
print("this is the json\(user)")
}catch{
print(error)
}
}.resume()
this is the log menu after i build :
"this is the jsonUser(command: nil, rowCount: nil, oid: nil, rows: nil)"
any idea where ive done wrong?
Your Codable structure is wrong. You should refer some tutorials for the same. Here is the Codable structure as per your response:
struct UserResponse: Codable {
let status: Int
let user: User
private enum CodingKeys: String, CodingKey {
case status
case user = " user"
}
}
struct User: Codable {
let command: String?
let rowCount: Int?
let oid: Int?
let rowCtor: Int?
let rowAsArray: Bool?
let rows: [Rows]?
let fields: [Fields]?
let parsers: [Parsers]?
let types: Type?
private enum CodingKeys: String, CodingKey {
case command
case rowCount
case oid
case rowCtor = "RowCtor"
case rowAsArray
case rows
case fields
case parsers = "_parsers"
case types = "_types"
}
}
struct Rows: Codable {
let userId: Int
let uName: String
let email: String
let divName: String
let url: String
private enum CodingKeys: String, CodingKey {
case userId = "user_id"
case uName = "u_name"
case email
case divName = "div_name"
case url
}
}
struct Fields: Codable {
let name: String
let tableID: Int
let columnID: Int
let datatypeID: Int?
let dataTypeSize: Int
let dataTypeModifier: Int
let format: String
private enum CodingKeys: String, CodingKey {
case name
case tableID
case columnID
case datatypeID
case dataTypeSize
case dataTypeModifier
case format
}
}
struct Parsers: Codable {
}
struct Types: Codable {
let types: Type?
let text: Text?
let binary: Binary?
private enum CodingKeys: String, CodingKey {
case types = "_types"
case text
case binary
}
}
struct Type: Codable {
}
struct Text: Codable {
}
struct Binary: Codable {
}
If any value can come as null, then only mark it as optional (?) otherwise don't, and in JSON your user key is having extra space at the front like " user", your API developer should fix it if possible.
Now decode it:
do{
let decodeResponse = try JSONDecoder().decode(UserResponse.self, from: data)
print("this is the json\(decodeResponse.user)")
}catch{
print(error)
}

How do I get this certain data set from json api in Swift?

I am currently using Tracker Networks Apex Legends API version 2.
I am trying to get the Legend’s data for each legend and then be able to show the data for each specific legend.
However, I cannot figure out an easy way of doing this.
Any ideas on how I could get something like...
Pathfinder
Kills - 100
Damage - 3000
Etc.
And do that for each legend.
JSON response:
{
"type": "legend",
"attributes": {
"id": "legend_8"
},
"metadata": {
"name": "Pathfinder",
"imageUrl": "https://trackercdn.com/cdn/apex.tracker.gg/legends/pathfinder-tile.png",
"tallImageUrl": "https://trackercdn.com/cdn/apex.tracker.gg/legends/pathfinder-tall.png",
"bgImageUrl": "https://trackercdn.com/cdn/apex.tracker.gg/legends/pathfinder-concept-bg-small.jpg",
"isActive": true
},
"expiryDate": "2019-10-04T21:59:04.1270197Z",
"stats": {
"kills": {
"rank": 208,
"percentile": 99.9,
"displayName": "Kills",
"displayCategory": "Combat",
"category": null,
"metadata": {},
"value": 12728,
"displayValue": "12,728",
"displayType": "Unspecified"
},
"killsAsKillLeader": {
"rank": 22,
"percentile": 99.9,
"displayName": "Kills As Kill Leader",
"displayCategory": "Combat",
"category": null,
"metadata": {},
"value": 5764,
"displayValue": "5,764",
"displayType": "Unspecified"
},
"sniperKills": {
"rank": 990,
"percentile": 99.7,
"displayName": "Sniper Kills",
"displayCategory": "Weapons",
"category": null,
"metadata": {},
"value": 104,
"displayValue": "104",
"displayType": "Unspecified"
},
"seasonWins": {
"rank": 31158,
"percentile": 92,
"displayName": "Season 1 Wins",
"displayCategory": "Game",
"category": null,
"metadata": {},
"value": 24,
"displayValue": "24",
"displayType": "Unspecified"
},
"seasonDamage": {
"rank": 5310,
"percentile": 98.8,
"displayName": "Season 1 Damage",
"displayCategory": "Game",
"category": null,
"metadata": {},
"value": 403954,
"displayValue": "403,954",
"displayType": "Unspecified"
}
}
},
"expiryDate": "2019-10-04T21:59:04.1270197Z"
}
You see I want to get this stats information for each legend and then display their name with whatever data on them is available inside a collection view or tableView. Probably collection view.
Structs used (done with QuickType):
struct Store: Codable {
let data: DataClass
enum CodingKeys: String, CodingKey {
case data = "data"
}
}
// MARK: - DataClass
struct DataClass: Codable {
let platformInfo: PlatformInfo
let userInfo: UserInfo
let metadata: DataMetadata
let segments: [Segment]
let availableSegments: [AvailableSegment]
//let expiryDate: ExpiryDate
enum CodingKeys: String, CodingKey {
case platformInfo = "platformInfo"
case userInfo = "userInfo"
case metadata = "metadata"
case segments = "segments"
case availableSegments = "availableSegments"
//case expiryDate = "expiryDate"
}
}
// MARK: - AvailableSegment
struct AvailableSegment: Codable {
let type: TypeEnum
let attributes: MetadataClass
enum CodingKeys: String, CodingKey {
case type = "type"
case attributes = "attributes"
}
}
// MARK: - MetadataClass
struct MetadataClass: Codable {
}
enum TypeEnum: String, Codable {
case legend = "legend"
case overview = "overview"
}
// MARK: - DataMetadata
struct DataMetadata: Codable {
let currentSeason: Int
let activeLegend: String
let activeLegendName: String
enum CodingKeys: String, CodingKey {
case currentSeason = "currentSeason"
case activeLegend = "activeLegend"
case activeLegendName = "activeLegendName"
}
}
// MARK: - PlatformInfo
struct PlatformInfo: Codable {
let platformSlug: String
let platformUserId: String
let platformUserHandle: String
let platformUserIdentifier: String
let avatarUrl: String
let additionalParameters: JSONNull?
enum CodingKeys: String, CodingKey {
case platformSlug = "platformSlug"
case platformUserId = "platformUserId"
case platformUserHandle = "platformUserHandle"
case platformUserIdentifier = "platformUserIdentifier"
case avatarUrl = "avatarUrl"
case additionalParameters = "additionalParameters"
}
}
// MARK: - Segment
struct Segment: Codable {
let type: TypeEnum
let attributes: SegmentAttributes
let metadata: SegmentMetadata
// let expiryDate: ExpiryDate
let stats: Stats
enum CodingKeys: String, CodingKey {
case type = "type"
case attributes = "attributes"
case metadata = "metadata"
//case expiryDate = "expiryDate"
case stats = "stats"
}
}
// MARK: - SegmentAttributes
struct SegmentAttributes: Codable {
let id: String?
enum CodingKeys: String, CodingKey {
case id = "id"
}
}
// MARK: - SegmentMetadata
struct SegmentMetadata: Codable {
let name: String
let imageUrl: String?
let tallImageUrl: String?
let bgImageUrl: String?
let isActive: Bool?
enum CodingKeys: String, CodingKey {
case name = "name"
case imageUrl = "imageUrl"
case tallImageUrl = "tallImageUrl"
case bgImageUrl = "bgImageUrl"
case isActive = "isActive"
}
}
// MARK: - Stats
struct Stats: Codable {
let level: ArKills?
let kills: ArKills
let damage: ArKills?
let headshots: ArKills?
let finishers: ArKills?
let arKills: ArKills?
let carePackageKills: ArKills?
let seasonWins: ArKills?
let seasonKills: ArKills?
let season2Wins: ArKills?
let rankScore: RankScore?
let smokeGrenadeEnemiesHit: ArKills?
let eyeEnemiesScanned: ArKills?
let grappleTravelDistance: ArKills?
enum CodingKeys: String, CodingKey {
case level = "level"
case kills = "kills"
case damage = "damage"
case headshots = "headshots"
case finishers = "finishers"
case arKills = "arKills"
case carePackageKills = "carePackageKills"
case seasonWins = "seasonWins"
case seasonKills = "seasonKills"
case season2Wins = "season2Wins"
case rankScore = "rankScore"
case smokeGrenadeEnemiesHit = "smokeGrenadeEnemiesHit"
case eyeEnemiesScanned = "eyeEnemiesScanned"
case grappleTravelDistance = "grappleTravelDistance"
}
}
// MARK: - ArKills
struct ArKills: Codable {
let rank: Int?
let percentile: Double?
let displayName: String
let displayCategory: DisplayCategory
let category: JSONNull?
let metadata: MetadataClass
let value: Double
let displayValue: String
let displayType: DisplayType
enum CodingKeys: String, CodingKey {
case rank = "rank"
case percentile = "percentile"
case displayName = "displayName"
case displayCategory = "displayCategory"
case category = "category"
case metadata = "metadata"
case value = "value"
case displayValue = "displayValue"
case displayType = "displayType"
}
}
enum DisplayCategory: String, Codable {
case combat = "Combat"
case game = "Game"
case weapons = "Weapons"
}
enum DisplayType: String, Codable {
case unspecified = "Unspecified"
}
// MARK: - RankScore
struct RankScore: Codable {
let rank: JSONNull?
let percentile: Int
let displayName: String
let displayCategory: DisplayCategory
let category: JSONNull?
let metadata: RankScoreMetadata
let value: Int
let displayValue: String
let displayType: DisplayType
enum CodingKeys: String, CodingKey {
case rank = "rank"
case percentile = "percentile"
case displayName = "displayName"
case displayCategory = "displayCategory"
case category = "category"
case metadata = "metadata"
case value = "value"
case displayValue = "displayValue"
case displayType = "displayType"
}
}
// MARK: - RankScoreMetadata
struct RankScoreMetadata: Codable {
let iconUrl: String
enum CodingKeys: String, CodingKey {
case iconUrl = "iconUrl"
}
}
// MARK: - UserInfo
struct UserInfo: Codable {
let isPremium: Bool
let isVerified: Bool
let isInfluencer: Bool
let countryCode: String
let customAvatarUrl: JSONNull?
let socialAccounts: JSONNull?
enum CodingKeys: String, CodingKey {
case isPremium = "isPremium"
case isVerified = "isVerified"
case isInfluencer = "isInfluencer"
case countryCode = "countryCode"
case customAvatarUrl = "customAvatarUrl"
case socialAccounts = "socialAccounts"
}
}
// 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 func hash(into hasher: inout Hasher) {
// No-op
}
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()
}
}
Code used for api call and displaying data:
let PlayerStatURL = URL(string: "https://public-api.tracker.gg/v2/apex/standard/profile/origin/itsspress")
if let unwrappedURL = PlayerStatURL {
var request = URLRequest(url: unwrappedURL)
request.addValue("db833c37-1f45-4be4-a670-38272dba7504", forHTTPHeaderField: "TRN-Api-Key")
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
// you should put in error handling code, too
if let data = data {
do {
let store = try JSONDecoder().decode(Store.self, from: data) as Store
print(store.data.platformInfo.avatarUrl)
print(store.data.platformInfo.platformUserHandle)
print("Level: \(store.data.segments[0].stats.level!.displayValue)")
print("lifetime Kills: \(store.data.segments.map{$0.stats.kills.displayValue}[0])")
print(store.data.segments.map{$0.metadata.name})
print(store.data.segments.map{$0.stats.carePackageKills?.displayName}[2])
} catch {
print(error.localizedDescription)
print(error)
}
}
}
dataTask.resume()
}
I am unsure how to get this data from the above JSON. The struct only seems to let me pull, let’s say kill stats, from all then legends and doesn’t let me just pull from let’s say pathfinder.
How could I just pull stats on pathfinder?
You can achieve that as below,
do {
let store = try JSONDecoder().decode(Store.self, from: data) as Store
store.data.segments.map{$0.metadata.name}.forEach { legendName in
if let stats = store.data.segments.first(where: { $0.metadata.name == legendName })?.stats {
let killString = stats.kills.displayName + " - " + stats.kills.displayValue
var damageString: String = ""
if let damage = stats.damage {
damageString = damage.displayName + " - " + damage.displayValue
}
print(legendName + " " + killString + " " + damageString )
}
}
} catch {
print(error.localizedDescription)
print(error)
}
Output:
Lifetime Kills - 408 Damage - 74,053
Pathfinder Kills - 230 Damage - 59,694
Gibraltar Kills - 1
Bangalore Kills - 116
Octane Kills - 0
Bloodhound Kills - 6
Wraith Kills - 18 Damage - 6,357
Mirage Kills - 14 Damage - 5,307
Caustic Kills - 7 Damage - 2,695
Lifeline Kills - 16

Swift: Parse data Codable protocol not working

I have a link that returns a json file, I try to print the data but it does not work it is always nil, here is the link:
http://heroapps.co.il/employee-tests/ios/logan.json
And my code:
struct DataClass: Codable {
let name: String?
let nickname: String?
let image: URL?
let dateOfBirth: Int?
let powers: [String]?
let actorName: String?
let movies: [Movie]?
enum CodingKeys: String, CodingKey {
case name = "name"
case nickname = "nickname"
case image = "image"
case dateOfBirth = "dateOfBirth"
case powers = "powers"
case actorName = "actorName"
case movies = "movies"
}
}
struct Movie: Codable {
let name: String?
let year: Int?
enum CodingKeys: String, CodingKey {
case name = "name"
case year = "year"
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
guard let gitUrl = URL(string: "http://heroapps.co.il/employee-tests/ios/logan.json") else { return }
URLSession.shared.dataTask(with: gitUrl) { (data, response, error) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let gitData = try decoder.decode(Movie.self, from: data)
print(gitData.name ?? "") //Print nil
} catch let err {
print("Err", err)
}
}.resume()
}
Thank you for helping me find where my error comes from, this is the first time I use this method to retrieve JSON data
You are not parsing the top level of the JSON. (success, errorCode, message and data).
Playground code for testing...
import Foundation
let jsonData = """
{
"success": true,
"errorCode": 0,
"message": "Succcess",
"data": {
"name": "Logan Howlett",
"nickname": "The Wolverine",
"image": "http://heroapps.co.il/employee-tests/ios/logan.jpg",
"dateOfBirth": 1880,
"powers": [
"Adamantium Bones",
"Self-Healing",
"Adamantium Claws"
],
"actorName": "Hugh Jackman",
"movies": [
{
"name": "X-Men Origins: Wolverine",
"year": 2009
},
{
"name": "The Wolverine",
"year": 2013
},
{
"name": "X-Men: Days of Future Past",
"year": 2014
},
{
"name": "Logan",
"year": 2017
}
]
}
}
""".data(using: .utf8)!
struct JSONResponse: Codable {
let success: Bool
let errorCode: Int
let message: String
let data: DataClass
}
struct DataClass: Codable {
let name: String?
let nickname: String?
let image: URL?
let dateOfBirth: Int?
let powers: [String]?
let actorName: String?
let movies: [Movie]?
enum CodingKeys: String, CodingKey {
case name = "name"
case nickname = "nickname"
case image = "image"
case dateOfBirth = "dateOfBirth"
case powers = "powers"
case actorName = "actorName"
case movies = "movies"
}
}
struct Movie: Codable {
let name: String?
let year: Int?
enum CodingKeys: String, CodingKey {
case name = "name"
case year = "year"
}
}
do {
let result = try JSONDecoder().decode(JSONResponse.self, from: jsonData)
print(result)
} catch {
print(error)
}