Parsing Nested JSON in Swift 4 with codable - json

I am trying to parse JSON using decodable in Swift 4
The JSON is as below:
{
"_id": {
"$oid": "5afceaa0c1743f37b4ee1cf8"
},
"Con_id": "xxx",
"S_id": "xxx",
"I_Image": [
{
"$binary": {
"base64": "",
"subType": "00"
}
}
],
"T_Agreements": [
{
"Ag_Type": "xxx",
"Ap_Type": "xxx",
"Header": {
"Date": {
"$numberInt": "0"
},
"Company": "xxx",
"O_Code": "xxx",
"Lo": "xxx",
"Completed": true
},
"T_Particular": {
"C_Name": "NA",
"C_Address": "NA",
"C_Landline": "NA",
"ROC": "NA",
"T_Name": "xxx",
"Gender": "M",
"NR": "xxx",
"Dob": "22/08/1977",
"C_No": "xxx",
"T_Address": "xxx",
"S_No": "xxx",
"Sign": "NA",
"Proposed": "xxx",
"Completed": true
},
"D_Agreement": {
"C_Period": {
"P_Yr": {
"$numberInt": "2"
},
"P_Mth": {
"$numberInt": "0"
},
"From": {
"$numberInt": "0"
},
"To": {
"$numberInt": "0"
}
},
"First_Term": {
"R_A": {
"$numberInt": "800000"
},
"From_Date": {
"$numberInt": "0"
},
"To_Date": {
"$numberInt": "0"
}
},
"Second_Term": {
"R_A": "0",
"From_Date": {
"$numberInt": "0"
},
"To_Date": {
"$numberInt": "0"
}
},
"S_D": {
"$numberInt": "800"
},
"S_D_M": {
"$numberInt": "0"
},
"C_F": {
"$numberInt": "0"
},
"D_C_F": {
"$numberInt": "0"
},
"Maintenance_Fee": {
"$numberInt": "0"
},
"Others": {
"Description": "NA",
"O_F": {
"$numberInt": "0"
}
},
"D_C": "NA",
"Completed": true
},
"T_S": {
"$binary": {
"base64": "",
"subType": "00"
}
},
"L_Rep": {
"Name": "xxx",
"Rep_Sig": {
"$binary": {
"base64": "",
"subType": "00"
}
}
},
"Remarks": ""
}
],
"Supp": {
"B_N": "xxx",
"B_O_H": "12",
"C_B_O": "xxx",
"A_S": "Nil",
"F_T_Description": "xxx",
"C_T": "xxx",
"Completed": true
},
"FAdjustment": [
{
"Date": {
"$numberInt": "0"
},
"R_Increased": true,
"Pro_R": {
"$numberInt": "20066660"
},
"A_P_From": {
"$numberInt": "0"
},
"A_P_To": {
"$numberInt": "0"
},
"E_Date": {
"$numberInt": "0"
},
"A_Reason": "xxx",
"Req": {
"Name": "xxx",
"Des": "xxx",
"Sig": {
"$binary": {
"base64": "",
"subType": "00"
}
},
"Date": {
"$numberInt": "0"
}
},
"A1": {
"Name": "xxx",
"Des": "xxx",
"Sig": {
"$binary": {
"base64": "",
"subType": "00"
}
},
"Date": {
"$numberInt": "0"
}
},
"A2": {
"Name": "xxx",
"Designation": "xxx",
"Sig": {
"$binary": {
"base64": "",
"subType": "00"
}
},
"Date": {
"$numberInt": "0"
}
}
}
],
"Status": "xxx",
"Re": {
"Out": "0"
},
"Termination": {
"Terminated": false,
"Reason": "NA"
}
}
I am able to easily parse things such as conID with my Struct:
struct Welcome: Codable {
let id: ID?
let conID, sID: String?
let iImage: [IImage]?
let tAgreements: [TAgreement]?
let supp: Supp?
let fAdjustment: [FAdjustment]?
let status: String?
let re: Re?
let termination: Termination?
enum CodingKeys: String, CodingKey {
case id = "_id"
case conID = "Con_id"
case sID = "S_id"
case iImage = "I_Image"
case tAgreements = "T_Agreements"
case supp = "Supp"
case fAdjustment = "FAdjustment"
case status = "Status"
case re = "Re"
case termination = "Termination"
}
}
struct FAdjustment: Codable {
let date: APFrom?
let rIncreased: Bool?
let proR, aPFrom, aPTo, eDate: APFrom?
let aReason: String?
let req, a1, a2: A1?
enum CodingKeys: String, CodingKey {
case date = "Date"
case rIncreased = "R_Increased"
case proR = "Pro_R"
case aPFrom = "A_P_From"
case aPTo = "A_P_To"
case eDate = "E_Date"
case aReason = "A_Reason"
case req = "Req"
case a1 = "A1"
case a2 = "A2"
}
}
struct A1: Codable {
let name, des: String?
let sig: IImage?
let date: APFrom?
let designation: String?
enum CodingKeys: String, CodingKey {
case name = "Name"
case des = "Des"
case sig = "Sig"
case date = "Date"
case designation = "Designation"
}
}
struct APFrom: Codable {
let numberInt: String?
enum CodingKeys: String, CodingKey {
case numberInt = "$numberInt"
}
}
struct IImage: Codable {
let binary: Binary?
enum CodingKeys: String, CodingKey {
case binary = "$binary"
}
}
struct Binary: Codable {
let base64, subType: String?
}
struct ID: Codable {
let oid: String?
enum CodingKeys: String, CodingKey {
case oid = "$oid"
}
}
struct Re: Codable {
let out: String?
enum CodingKeys: String, CodingKey {
case out = "Out"
}
}
struct Supp: Codable {
let bN, bOH, cBO, aS: String?
let fTDescription, cT: String?
let completed: Bool?
enum CodingKeys: String, CodingKey {
case bN = "B_N"
case bOH = "B_O_H"
case cBO = "C_B_O"
case aS = "A_S"
case fTDescription = "F_T_Description"
case cT = "C_T"
case completed = "Completed"
}
}
struct TAgreement: Codable {
let agType, apType: String?
let header: Header?
let tParticular: TParticular?
let dAgreement: DAgreement?
let tS: IImage?
let lRep: LRep?
let remarks: String?
enum CodingKeys: String, CodingKey {
case agType = "Ag_Type"
case apType = "Ap_Type"
case header = "Header"
case tParticular = "T_Particular"
case dAgreement = "D_Agreement"
case tS = "T_S"
case lRep = "L_Rep"
case remarks = "Remarks"
}
}
struct DAgreement: Codable {
let cPeriod: CPeriod?
let firstTerm: FirstTerm?
let secondTerm: SecondTerm?
let sD, sDM, cF, dCF: APFrom?
let maintenanceFee: APFrom?
let others: Others?
let dC: String?
let completed: Bool?
enum CodingKeys: String, CodingKey {
case cPeriod = "C_Period"
case firstTerm = "First_Term"
case secondTerm = "Second_Term"
case sD = "S_D"
case sDM = "S_D_M"
case cF = "C_F"
case dCF = "D_C_F"
case maintenanceFee = "Maintenance_Fee"
case others = "Others"
case dC = "D_C"
case completed = "Completed"
}
}
struct CPeriod: Codable {
let pYr, pMth, from, to: APFrom?
enum CodingKeys: String, CodingKey {
case pYr = "P_Yr"
case pMth = "P_Mth"
case from = "From"
case to = "To"
}
}
struct FirstTerm: Codable {
let rA, fromDate, toDate: APFrom?
enum CodingKeys: String, CodingKey {
case rA = "R_A"
case fromDate = "From_Date"
case toDate = "To_Date"
}
}
struct Others: Codable {
let description: String?
let oF: APFrom?
enum CodingKeys: String, CodingKey {
case description = "Description"
case oF = "O_F"
}
}
struct SecondTerm: Codable {
let rA: String?
let fromDate, toDate: APFrom?
enum CodingKeys: String, CodingKey {
case rA = "R_A"
case fromDate = "From_Date"
case toDate = "To_Date"
}
}
struct Header: Codable {
let date: APFrom?
let company, oCode, lo: String?
let completed: Bool?
enum CodingKeys: String, CodingKey {
case date = "Date"
case company = "Company"
case oCode = "O_Code"
case lo = "Lo"
case completed = "Completed"
}
}
struct LRep: Codable {
let name: String?
let repSig: IImage?
enum CodingKeys: String, CodingKey {
case name = "Name"
case repSig = "Rep_Sig"
}
}
struct TParticular: Codable {
let cName, cAddress, cLandline, roc: String?
let tName, gender, nr, dob: String?
let cNo, tAddress, sNo, sign: String?
let proposed: String?
let completed: Bool?
enum CodingKeys: String, CodingKey {
case cName = "C_Name"
case cAddress = "C_Address"
case cLandline = "C_Landline"
case roc = "ROC"
case tName = "T_Name"
case gender = "Gender"
case nr = "NR"
case dob = "Dob"
case cNo = "C_No"
case tAddress = "T_Address"
case sNo = "S_No"
case sign = "Sign"
case proposed = "Proposed"
case completed = "Completed"
}
}
struct Termination: Codable {
let terminated: Bool?
let reason: String?
enum CodingKeys: String, CodingKey {
case terminated = "Terminated"
case reason = "Reason"
}
}
I'm struggling with getting the nested stuff out.
How do I get things from T_Agreements like Ag_Type out individually and everything from T_Particular out individually?
I have tried
let jsonUrlString = "URL REMOVED REFER TO JSON ABOVE"
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()
let welcome = try! decoder.decode(Welcome.self, from: data)
let tagree = try! decoder.decode(TAgreement.self, from: data)
print(tagree) // This returns all the header inside T_Agreements but the values are all nil
print(tagree.tParticular.cAddress) // This returns nil too
}
}.resume()
Much thanks and appreciation

The line let welcome = try! decoder.decode(Welcome.self, from: data) loads the json data into a Welcome data model, which matches the structure of the json. Trying to reload the same json data into other data models (as you do in the next line) won't work. You need to extract the data directly from the populated data models you've created.
To get TAgreements, you just grab that data from the welcome model:
let tagreements = welcome.tAgreements
To get Ag_Type out, you get the populated data from the first element of tagreements:
let agType = tagreements[0].agType

Related

SwiftUI - Decoding a JSON returns blank screen

I am trying to decode a JSON object from a remote API, Xcode doesn't raise any flags but the screen remains blank, I couldn't pinpoint where the error is coming from but if I have to take I guess, I think it's something to do with my parsing.
What's going wrong here? everything seems at its place
This is my ContentView.swift
import SwiftUI
struct ContentView: View {
#State var results = UserProducts(status: Bool(), userProducts: [UserProduct]())
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: nil) {
ForEach(0..<results.userProducts!.count) {
res in
VStack(){Text(verbatim: String(format: String(),((results.userProducts![res].id ?? "NA"))))}
}.onAppear(perform: loadShelf)
}
}
Spacer()
}).background(Color(red: 250 / 255, green: 248 / 255, blue: 244 / 255))
}
func loadShelf(){
guard let apiBaseURL = URL(string: "...") else {
print("Base URL is invalid.")
return
}
let request = URLRequest(url: apiBaseURL)
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
if let data = data {
do{
let decoded = try JSONDecoder().decode(UserProducts.self, from: data)
self.results = decoded
print("decoded: \(decoded)")
//prints: UserProducts(status: nil, userProducts: nil, recommendedProducts: nil)
}
catch{
print("Fetching data failed: \(error)")
}
}
}
}.resume()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This is my Structs:
import Foundation
// MARK: - UserProducts
struct UserProducts: Codable {
let status: Bool?
let userProducts: [UserProduct]?
enum CodingKeys: String, CodingKey {
case status
case userProducts = "user_products"
}
}
// MARK: - UserProduct
struct UserProduct: Codable {
let id, userID, productID: Int?
let routineTime, createdAt, updatedAt: String?
let archived, volume: Int?
let deletedAt, addedBy, weeklyRoutineOne, weeklyRoutineTwo: String?
let product: Product?
let user: User?
let phaseOut, refill, empty, recommended: Int?
enum CodingKeys: String, CodingKey {
case id
case userID = "user_id"
case productID = "product_id"
case routineTime = "routine_time"
case createdAt = "created_at"
case updatedAt = "updated_at"
case archived, volume
case deletedAt = "deleted_at"
case addedBy = "added_by"
case weeklyRoutineOne = "weekly_routine_one"
case weeklyRoutineTwo = "weekly_routine_two"
case product, user
case phaseOut = "phase_out"
case refill, empty, recommended
}
}
// MARK: - Product
struct Product: Codable {
let productName, productDescription, productIngredients: String?
let productPrice, volume: Int?
let image, interference, activeIngredients, howToUse: String?
let brandID, productTypeID: Int?
let brand, type: Brand?
let rating: JSONNull?
enum CodingKeys: String, CodingKey {
case productName = "product_name"
case productDescription = "product_description"
case productIngredients = "product_ingredients"
case productPrice = "product_price"
case volume, image, interference
case activeIngredients = "active_ingredients"
case howToUse = "how_to_use"
case brandID = "brand_id"
case productTypeID = "product_type_id"
case brand, type, rating
}
}
// MARK: - Brand
struct Brand: Codable {
let id: Int?
let name, createdAt, updatedAt, commission: String?
let category: Int?
enum CodingKeys: String, CodingKey {
case id, name
case createdAt = "created_at"
case updatedAt = "updated_at"
case commission, category
}
}
// MARK: - User
struct User: Codable {
let name, email: String?
let image1, deviceToken: JSONNull?
let account, followup: Bool?
enum CodingKeys: String, CodingKey {
case name, email, image1
case deviceToken = "device_token"
case account, followup
}
}
// 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()
}
}
Now this is the JSON model and how it's supposed to look:
{
"status": true,
"user_products": [
{
"id": 1,
"user_id": 1,
"product_id": 1,
"routine_time": "",
"created_at": "",
"updated_at": "",
"archived": 0,
"volume": 1,
"deleted_at": "",
"added_by": "",
"weekly_routine_one": "",
"weekly_routine_two": "",
"product": {
"product_name": "",
"product_description": "",
"product_ingredients": "",
"product_price": 1,
"volume": 1,
"image": "",
"interference": "",
"active_ingredients": "",
"how_to_use": "",
"brand_id": 1,
"product_type_id": 1,
"brand": {
"id": 1,
"name": "",
"created_at": "",
"updated_at": "",
"commission": ""
},
"type": {
"id": 1,
"name": "",
"created_at": "",
"updated_at": "",
"category": 1
},
"rating": null
},
"user": {
"name": "",
"email": "",
"image1": null,
"device_token": null,
"account": false,
"followup": false
},
"phase_out": 0,
"refill": 0,
"empty": 0,
"recommended": 0
}
]
}
You actually have two problems here.
1st, this is where your nils are coming from:
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
If you comment it out or make it do what you actually want it to do instead of what it's currently doing (making everything nil)... that'll bring us to problem #2
You'll have your data, but because it's all optionals, there's some unwrapping that needs to be done before it'll make much sense.

Swift: search for json key and edit it

I writing because I need to search a json-key passed in a function like a string. Do you have any suggestion on how I could implement it? Once I find the key I also need to edit the value. Here there is the code I wrote until now:
JSON:
{
"JSONRoot": {
"version": 1,
"Town": {
"hour": 0,
"latitude": "",
"longitude": 0,
"latitudine": 0
},
"MeasurePoints": {
"MeasurePoint": [
{
"code": "",
"codelocation": "",
}
]
},
"Wakeup": {
"startH": 6,
"startM": 0,
"maxAttempts": 3,
"maxRetry": 10
},
"Config": {
"port": 12345,
"A": {
"writable": true,
"value": 12
},
"B": {
"writable": true,
"value": 8
},
},
"Sales": {
"Stores": {
"Store": [
{
"description": "A description",
"type": "1",
"Floors": {
"basement": true,
"number": 2
},
"Doors": {
"type": "",
"number": 7
},
"Lights": {
"number": 20
}
},
{
"description": "A description",
"type": "4",
"Floors": {
"basement": none,
"number": 1
},
"Doors": {
"type": "",
"number": 4
},
"Lights": {
"number": 8
}
}
]
}
}
}
}
Structs with codable:
// MARK: - JSONConfig
struct JsonConfig: Codable {
let jsonRoot: JSONRoot?
enum CodingKeys: String, CodingKey {
case jsonRoot = "JSONRoot"
}
}
// MARK: - JSONRoot
struct JSONRoot: Codable {
let version: Int?
let measurePoints: MeasurePoints?
let wakeup: Wakeup?
let config: Config?
let sale: Sale?
enum CodingKeys: String, CodingKey {
case version
case measurePoints = "MeasurePoints"
case wakeup = "Wakeup"
case config = "Config"
case sale = "Sale"
}
}
// MARK: - Stores
struct Stores: Codable {
let stores: [Store]?
enum CodingKeys: String, CodingKey {
case stores = "Stores"
}
}
// MARK: - Store
struct Store: Codable {
let storeDescription: String?
let type: Int?
let floors: Floors?
let doors: Doors?
let lights: Lights?
enum CodingKeys: String, CodingKey {
case storeDescription = "description"
case type
case floors = "Floors"
case doors = "Doors"
case lights = "Lights"
}
}
// MARK: - Floors
struct Floors: Codable {
let basement: Bool?
let number: Int?
}
// MARK: - Doors
struct Doors: Codable {
let type: String?
let number: Int?
}
// MARK: - Lights
struct Lights: Codable {
let number: Int?
}
// MARK: - MeasurePoints
struct MeasurePoints: Codable {
let measurePoint: [MeasurePoint]?
enum CodingKeys: String, CodingKey {
case measurePoint = "MeasurePoint"
}
}
// MARK: - MeasurePoint
struct MeasurePoint: Codable {
let code, codeLocation: String?
}
// MARK: - Config
struct Config: Codable {
let port: Int?
let a, b: K?
enum CodingKeys: String, CodingKey {
case port
case a = "A"
case b = "B"
}
}
// MARK: - K
struct K: Codable {
let writable: Bool?
let value: Int?
}
// MARK: - Wakeup
struct Wakeup: Codable {
let startH, startM, maxAttempts, maxRetry: Int?
}
Function to search for a key:
func setKeyValue(jsonKey: String, value: String) {
let decoder = JSONDecoder()
let jsonData = Data(C.jsonString.utf8)
if let jsonResult = try? decoder.decode(JsonConfig.self, from: jsonData) {
// At this point I have the jsonKey = "JSONRoot.Wakeup.maxRetry" but how I can use it to search for
// the key in the jsonResult?
}
}
Obviously I need to create a new struct to edit the json but one step at a time.
Using JSONSerialisation is probably the most straightforward way here
var value: Any?
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
let keys = "JSONRoot.Wakeup.maxRetry".split(separator: ".").map {String($0)}
var dict = jsonResult
for i in 0..<keys.count {
if let temp = dict[keys[i]] as? [String:Any] {
dict = temp
continue
}
value = dict[keys[i]]
}
}
} catch {
print(error)
}
Note that this doesn't support arrays but a solution for that is very dependent on how the search key syntax would handle an array
If my thinking is correct as you, you can try with this code.
override func viewDidLoad() {
super.viewDidLoad()
let jsonString = """
{
"JSONRoot": {
"version": 1,
"Town": {
"hour": 0,
"latitude": "",
"longitude": 0,
"latitudine": 0
},
"MeasurePoints": {
"MeasurePoint": [{
"code": "",
"codelocation": ""
}]
},
"Wakeup": {
"startH": 6,
"startM": 0,
"maxAttempts": 3,
"maxRetry": 10
},
"Config": {
"port": 12345,
"A": {
"writable": true,
"value": 12
}
},
"Sales": {
"Stores": {
"Store": [{
"description": "A description",
"type": "1",
"Floors": {
"basement": true,
"number": 2
},
"Doors": {
"type": "",
"number": 7
},
"Lights": {
"number": 20
}
},
{
"description": "A description",
"type": "4",
"Floors": {
"basement": "none",
"number": 1
},
"Doors": {
"type": "",
"number": 4
},
"Lights": {
"number": 8
}
}
]
}
}
}
}
"""
editJson(jsonString)
}
func editJson(_ jsonString: String) {
do{
let jsonData = Data(jsonString.utf8)
var jsonObject = try JSONSerialization.jsonObject(with: jsonData)
parseDict(&jsonObject)
print("jsonObject: \(String(describing: jsonObject))")
}catch let error {
print(error.localizedDescription)
}
}
func parseDict(_ jsonObject: inout Any) {
if let _ = jsonObject as? String {
return
} else if var dictionary = jsonObject as? Dictionary<String, Any> {
for (key, value) in dictionary {
var nextObject = value
parseDict(&nextObject)
if let value = getValueWith(key), let _ = dictionary.removeValue(forKey: key) {
dictionary[key] = value
} else {
dictionary[key] = nextObject
}
}
jsonObject = dictionary
}else if let array = jsonObject as? Array<Any> {
var updatedArray = array
for (index, value) in array.enumerated() {
var nextObject = value
parseDict(&nextObject)
updatedArray[index] = nextObject
}
jsonObject = updatedArray
}
}
func getValueWith(_ key: String) -> String? {
return [
"description" : "Amit (amitpstu1#gmail.com) ... so on"
][key]
}
You can refresh your memory or learn more here:
https://developer.apple.com/documentation/foundation/archives_and_serialization/using_json_with_custom_types
You would be looking at merge json from different depths section. Using encodable extension etc.
You could also look here: In Swift, can one use a string to access a struct property? If you want to roll your own search function, like a modified dfs or something.

Parsing nested json response data using codable in iOS Swift?

I am trying to parse json data in decodable in swift 4. It prints nil value. i could not find what issue is this?
here is model class:
public struct TaskID: Decodable {
let embedded: Embedded?
let count: Int?
enum CodingKeys: String, CodingKey {
case count = "count"
case embedded = "_embedded"
}
}
public struct Embedded: Decodable {
let task: [Task]?
enum CodingKeys: String, CodingKey {
case task = "task"
}
}
public struct Task : Decodable {
let id : String?
let name: String?
let assignee: String?
let created: String?
let processDefinitionId: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
case assignee = "assignee"
case created = "created"
case processDefinitionId = "processDefinitionId"
}
}
Here is json:
{
"_links": {
"self": {
"href": "/task"
}
},
"_embedded": {
"task": [
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": []
},
"id": "1b64f688-0616-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-13T13:04:20.687+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
},
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": [
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/loanAmount"
}
},
"_embedded": null,
"name": "loanAmount",
"value": "650000",
"type": "String",
"valueInfo": {}
},
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/firstName"
}
},
"_embedded": null,
"name": "firstName",
"value": "Kamesh",
"type": "String",
"valueInfo": {}
}
]
},
"id": "412a2aca-06ae-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-14T07:13:27.558+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
}
]
},
"count": 13
}
Here is urlrequest:
// MARK: - URLRequestConvertible
func asURLRequest() throws -> URLRequest {
let url = try K.ProductionServer.baseURL.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
print(urlRequest)
// HTTP Method
urlRequest.httpMethod = method.rawValue
let authToken = UserDefaults.standard.string(forKey: "authToken")
let bearerToken: String = "Bearer " + (authToken ?? "")
print("baearer token::\(bearerToken)")
// Common Headers
urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.acceptType.rawValue)
urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.contentType.rawValue)
urlRequest.setValue(bearerToken, forHTTPHeaderField: HTTPHeaderField.authentication.rawValue)
// Parameters
if let parameters = parameters {
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
}
return urlRequest
}
Here is alamofire request:
import Foundation
import Alamofire
public class APIClient {
#discardableResult
private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:#escaping (AFResult<T>)->Void) -> DataRequest {
return AF.request(route)
.responseDecodable (decoder: decoder){ (response: AFDataResponse<T>) in
completion(response.result)
print("framework response::",response.result)
}
}
public static func taskID(id: String, completion:#escaping (AFResult< [TaskID]>)->Void) {
performRequest(route: APIRouter.TaskById(id: id), completion: completion)
}
}//APIClient
Initially it shows Dictionary, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary but found an array instead. but now i'm getting nil in console log. Do not know why i'm getting nil value. Is struct is correct based on my json response? I'm struggling with getting the nested data.
Any help much appreciated pls..
Your struct is correct. See playground below for proof; I don't get an error. nil is very common result when you don't have the entire data set and you assume that some optional field in the response is non optional just because you see it in your sample data (your sample is not necessarily representative). Absent an actual spec from the server, you need to figure out what field is failing to decode and you may need to get a bunch of data to figure out which fields are really optional. You can do that by either putting in error handling code in your AF project above or just by pasting your response into my playground below. Either way the decoding error should tell you which field was not present.
import PlaygroundSupport
import UIKit
import WebKit
public struct TaskID: Decodable {
let embedded: Embedded?
let count: Int?
enum CodingKeys: String, CodingKey {
case count = "count"
case embedded = "_embedded"
}
}
public struct Embedded: Decodable {
let task: [Task]?
enum CodingKeys: String, CodingKey {
case task = "task"
}
}
public struct Task : Decodable {
let id : String?
let name: String?
let assignee: String?
let created: String?
let processDefinitionId: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
case assignee = "assignee"
case created = "created"
case processDefinitionId = "processDefinitionId"
}
}
let data = """
{
"_links": {
"self": {
"href": "/task"
}
},
"_embedded": {
"task": [
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": []
},
"id": "1b64f688-0616-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-13T13:04:20.687+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
},
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": [
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/loanAmount"
}
},
"_embedded": null,
"name": "loanAmount",
"value": "650000",
"type": "String",
"valueInfo": {}
},
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/firstName"
}
},
"_embedded": null,
"name": "firstName",
"value": "Kamesh",
"type": "String",
"valueInfo": {}
}
]
},
"id": "412a2aca-06ae-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-14T07:13:27.558+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
}
]
},
"count": 13
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let decoded = try decoder.decode(TaskID.self, from: data)
print(decoded)
} catch ( let error ) {
print(error.localizedDescription)
}
import Foundation
// MARK: - Task
struct Task: Codable {
let links: VariableLinks?
let embedded: TaskEmbedded?
let count: Int?
enum CodingKeys: String, CodingKey {
case links = "_links"
case embedded = "_embedded"
case count = "count"
}
}
// MARK: - TaskEmbedded
struct TaskEmbedded: Codable {
let task: [TaskElement]?
enum CodingKeys: String, CodingKey {
case task = "task"
}
}
// MARK: - TaskElement
struct TaskElement: Codable {
let links: TaskLinks?
let embedded: TaskEmbeddedClass?
let id: String?
let name: String?
let assignee: String?
let created: String?
let due: String?
let followUp: String?
let delegationState: String?
let taskDescription: String?
let executionId: String?
let owner: String?
let parentTaskId: Int?
let priority: Int?
let processDefinitionId: String?
let processInstanceId: String?
let taskDefinitionKey: String?
let caseExecutionId: Int?
let caseInstanceId: Int?
let caseDefinitionId: Int?
let suspended: Bool?
let formKey: String?
let tenantId: Int?
enum CodingKeys: String, CodingKey {
case links = "_links"
case embedded = "_embedded"
case id = "id"
case name = "name"
case assignee = "assignee"
case created = "created"
case due = "due"
case followUp = "followUp"
case delegationState = "delegationState"
case taskDescription = "description"
case executionId = "executionId"
case owner = "owner"
case parentTaskId = "parentTaskId"
case priority = "priority"
case processDefinitionId = "processDefinitionId"
case processInstanceId = "processInstanceId"
case taskDefinitionKey = "taskDefinitionKey"
case caseExecutionId = "caseExecutionId"
case caseInstanceId = "caseInstanceId"
case caseDefinitionId = "caseDefinitionId"
case suspended = "suspended"
case formKey = "formKey"
case tenantId = "tenantId"
}
}
// MARK: - TaskEmbeddedClass
struct TaskEmbeddedClass: Codable {
let variable: [Variable]?
enum CodingKeys: String, CodingKey {
case variable = "variable"
}
}
// MARK: - Variable
struct Variable: Codable {
let links: VariableLinks?
let embedded: String?
let name: String?
let value: String?
let type: String?
let valueInfo: ValueInfo?
enum CodingKeys: String, CodingKey {
case links = "_links"
case embedded = "_embedded"
case name = "name"
case value = "value"
case type = "type"
case valueInfo = "valueInfo"
}
}
// MARK: - VariableLinks
struct VariableLinks: Codable {
let linksSelf: SelfClass?
enum CodingKeys: String, CodingKey {
case linksSelf = "self"
}
}
// MARK: - SelfClass
struct SelfClass: Codable {
let href: String?
enum CodingKeys: String, CodingKey {
case href = "href"
}
}
// MARK: - ValueInfo
struct ValueInfo: Codable {
}
// MARK: - TaskLinks
struct TaskLinks: Codable {
let assignee: SelfClass?
let execution: SelfClass?
let identityLink: SelfClass?
let processDefinition: SelfClass?
let processInstance: SelfClass?
let linksSelf: SelfClass?
enum CodingKeys: String, CodingKey {
case assignee = "assignee"
case execution = "execution"
case identityLink = "identityLink"
case processDefinition = "processDefinition"
case processInstance = "processInstance"
case linksSelf = "self"
}
}
Also, if you feeling lazy you can use quicktype.io, As nil is a very common response from decodable, you can you an extension for DataRequest to parse and get the values from the request just like using responseDecodable, here you can use something like this,
extension DataRequest {
fileprivate func decodableResponseSerializer<T: Decodable>() -> DataResponseSerializer<T> {
return DataResponseSerializer { _, response, data, error in
guard error == nil else { return .failure(error!) }
guard let data = data else {
return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
}
return Result { try newJSONDecoder().decode(T.self, from: data) }
}
}
#discardableResult
fileprivate func responseDecodable<T: Decodable>(queue: DispatchQueue? = nil, completionHandler: #escaping (DataResponse<T>) -> Void) -> Self {
return response(queue: queue, responseSerializer: decodableResponseSerializer(), completionHandler: completionHandler)
}
}
and then you can call it like this
Alamofire.request(url, method:.post, parameters: parameters, headers: headers)
.responseDecodable { (response: DataResponse< Task >) in completion(response.result) }
as you were getting something like this, it only comes when you have a different type of data rather than which you have specified.

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