I'm trying to fetch data from swift 4 and I'm having nil as response.
1- I have this piece of code and I have the error "Type 'JobSeekerDataAPI' does not conform to protocol 'Decodable'
import UIKit
import SwiftyJSON
struct JobSeekerDataAPI : Decodable {
let job_seeker_id: String?
let job_seeker_name: String?
let linkedin_id: String?
let first_name: String?
let last_name: String?
let user_id: String?
let profile_pic_file: String?
let personal_job_title: String?
let about: String?
let interest: String?
let most_recent_work_history_id: String?
let most_recent_education_id: String?
let rel_work_exp_year: String?
let most_recent_salary: String?
let salary_expectation_high: String?
let salary_expectation_low: String?
let is_salary_on_public_profile: String?
let education_level_id: String?
let location_country_id: String?
let location_timezone_id: String?
let work_eligibility_id: String?
let public_seeking_status_id: String?
let search_seeking_status_id: String?
let days_before_begin_new_job: String?
let disc_self_d: String?
let disc_self_i: String?
let disc_self_s: String?
let disc_self_c: String?
let location_postal_code: String?
let will_relocate: String?
let is_default: String?
let is_military: String?
let website_url: String?
let contact_email: String?
let contact_mobile: String?
let contact_alt_phone: String?
let sort_order: String?
let disc_adj_nd_id: String?
let disc_adj_ni_id: String?
let disc_adj_ns_id: String?
let disc_adj_nc_id: String?
let disc_adj_lw_id: String?
let talent_filter_01: String?
let talent_filter_02: String?
let talent_filter_03: String?
let talent_filter_04: String?
let talent_filter_05: String?
let talent_filter_10: String?
let talent_filter_11: String?
let talent_filter_12: String?
let talent_filter_13: String?
let talent_filter_14: String?
let talent_filter_15: String?
let talent_filter_16: String?
let talent_filter_17: String?
let talent_filter_18: String?
let talent_filter_19: String?
let profileSlug: String?
let mostRecentWorkHistory: [String:String]?
let priorWorkHistories: [WorkHistory]?
let mostRecentEducationHistory: [EducationHistory]?
let priorEducationHistories: [EducationHistory]?
let topQualifications: [TopQualifications]?
let seekingLocations: String?
let education_level: EducationLevel?
let location_country: LocationCountry?
let location_timezone: LocationTimeZone?
let work_eligibility: WorkEligibility?
let public_seeking_status: SeekingStatus?
let search_seeking_status: SeekingStatus?
let most_recent_work_history: WorkHistory?
let most_recent_education: EducationHistory?
let disc_adj_nd: DiscAdjData?
let disc_adj_ni: DiscAdjData?
let disc_adj_ns: DiscAdjData?
let disc_adj_nc: DiscAdjData?
let disc_adj_lw: DiscAdjData?
let js_employer_excludes: [String]?
let js_media: [String]?
let js_occupations: [JSOccupation]?
let js_search_places: [JSSearchPlaces]?
let js_work_types: [JSWorkTypes]?
let userCoWorkers: [String]?
enum CodingKeys: String, CodingKey {
case jobSeekerID = "job_seeker_id"
case jobseekerName = "job_seeker_name"
case linkedInId = "linkedin_id"
case firstName = "first_name"
case lastName = "last_name"
case userID = "user_id"
case profilePicture = "profile_pic_file"
case personalJobTitle = "personal_job_title"
case aboutUser = "about"
case userInterest = "interest"
case mostRecentWorkHistoryId = "most_recent_work_history_id"
case mostRecentEducationId = "most_recent_education_id"
case workExperienceYear = "rel_work_exp_year"
case mostRecentSalary = "most_recent_salary"
case salaryExpectationHigh = "salary_expectation_high"
case salaryExpectationLow = "salary_expectation_low"
case salaryVisiblePublicProf = "is_salary_on_public_profile"
case educationLevelID = "education_level_id"
case locationCountryID = "location_country_id"
case locationTimezoneID = "location_timezone_id"
case workEligibilityID = "work_eligibility_id"
case publicSeekingStatusID = "public_seeking_status_id"
case searchSeekingStatusID = "search_seeking_status_id"
case daysBeforeBeguinJob = "days_before_begin_new_job"
case discSelfD = "disc_self_d"
case discSelfI = "disc_self_i"
case discSelfS = "disc_self_s"
case discSelfC = "disc_self_c"
case locationPostalCode = "location_postal_code"
case willRelocate = "will_relocate"
case isDefault = "is_default"
case isMilitary = "is_military"
case websiteURL = "website_url"
case contactEmail = "contact_email"
case contactMobile = "contact_mobile"
case contactAlternativePhone = "contact_alt_phone"
case sortOrder = "sort_order"
case discAdjNDID = "disc_adj_nd_id"
case discAdjNIID = "disc_adj_ni_id"
case discAdjNSID = "disc_adj_ns_id"
case discAdjNCID = "disc_adj_nc_id"
case discAdjLWID = "disc_adj_lw_id"
//probably bool value
case talentFilter01 = "talent_filter_01"
case talentFilter02 = "talent_filter_02"
case talentFilter03 = "talent_filter_03"
case talentFilter04 = "talent_filter_04"
case talentFilter05 = "talent_filter_05"
case talentFilter10 = "talent_filter_10"
case talentFilter11 = "talent_filter_11"
case talentFilter12 = "talent_filter_12"
case talentFilter13 = "talent_filter_13"
case talentFilter14 = "talent_filter_14"
case talentFilter15 = "talent_filter_15"
case talentFilter16 = "talent_filter_16"
case talentFilter17 = "talent_filter_17"
case talentFilter18 = "talent_filter_18"
case talentFilter19 = "talent_filter_19"
case profileSlug = "profile_slug"
case mostRecentWorkHistoryArray = "mostRecentWorkHistory"
case priorWorkHistoriesArray = "priorWorkHistories"
case mostRecentEducationHistoryArray = "mostRecentEducationHistory"
case priorEducationHistoryArray = "priorEducationHistories"
case topQUalificationsArray = "topQualifications"
case seekingLocations = "seekingLocations"
case educationLevel = "education_level"
case locationCountry = "location_country"
case locationTimeZone = "location_timezone"
case workEligibility = "WorkEligibility"
case publicSeekingStatus = "public_seeking_status"
case searchSeekingStatus = "search_seeking_status"
case discAdjND = "disc_adj_nd"
case discAdjNI = "disc_adj_ni"
case discAdjNS = "disc_adj_ns"
case discAdjNC = "disc_adj_nc"
case discAdjLW = "disc_adj_lw"
case jobSeekerEmployerExcludes = "js_employer_excludes"
case jobSeekerMedia = "js_media"
case jobSeekerOccupationsArray = "js_occupations"
case jobSeekerSearchPlacesArray = "js_search_places"
case jobSeekerWorkTypes = "js_work_types"
case userCoWorkers = "user_coworkers"
}
}
struct WorkHistory: Decodable{
let work_history_id : String?
let job_seeker_id: String?
let position: String?
let employer: String?
let work_history_name: String?
let work_type_id: String?
let responsibilities: String?
let reason_for_leaving: String?
let is_current_position: String?
let start_month: String?
let start_year: String?
let end_month: String?
let end_year: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
//
// case workHistoryID = "work_history_id"
// case jobSeekerID = "job_seeker_id"
// case position = "position"
// case employer = "employer"
// case workHistoryName = "work_history_name"
// case workTypeId = "work_type_id"
// case responsabilities = "responsibilities"
// case reasonForLeaving = "reason_for_leaving"
// case isCurrentPosition = "is_current_position"
// case startMonth = "start_month"
// case startYear = "start_year"
// case finishMonth = "end_month"
// case finishYear = "end_year"
// case sortOrder = "sort_order"
// }
}
struct EducationHistory: Decodable {
let education_history_id: String?
let job_seeker_id: String?
let education_level: String?
let start_month: String?
let start_year: String?
let end_month: String?
let end_year: String?
let educational_institution: String?
let program_major: String?
let education_history_name: String?
let cumulative_gpa: String?
let major_gpa: String?
let currently_attending: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
//
// case educationID = "education_history_id"
// case jobSeekerID = "job_seeker_id"
// case educationLevel = "education_level"
// case startMonth = "start_month"
// case startYear = "start_year"
// case endMonth = "end_month"
// case endYear = "end_year"
// case educationalInstitution = "educational_institution"
// case programMajor = "program_major"
// case educationalHistoryName = "education_history_name"
// case cumulativeGPA = "cumulative_gpa"
// case majorGPA = "major_gpa"
// case currentlyAttending = "currently_attending"
// case sortEducationOrder = "sort_order"
// }
}
struct TopQualifications: Decodable {
let requirement_id: String?
let requirement_name: String?
let requirement_descr: String?
let req_category_id: String?
let req_type_id: String?
let for_all_occupations: String?
// enum CodingKeys: String, CodingKey {
//
// case requirementID = "requirement_id"
// case requirementName = "requirement_name"
// case requirementDescription = "requirement_descr"
// case requirementCategoryID = "req_category_id"
// case requirementTypeID = "req_type_id"
// case forAllOccupations = "for_all_occupations"
// }
}
struct EducationLevel: Decodable {
let education_level_id: String?
let education_level_name: String?
let education_level_code: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
//
// case educationLevelID = "education_level_id"
// case edcationLevelName = "education_level_name"
// case educationLevelCode = "education_level_code"
// case sortOrder = "sort_order"
// }
}
struct LocationCountry: Decodable {
let location_country_id: String?
let location_country_name: String?
let location_country_code: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
//
// case locationCountryID = "location_country_id"
// case locationCountryName = "location_country_name"
// case locationCountruyCode = "location_country_code"
// case sortOrder = "sort_order"
// }
}
struct LocationTimeZone: Decodable {
let location_timezone_id: String?
let location_timezone_name: String?
let location_timezone_code: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
// case locationTimeZoneID = "location_timezone_id"
// case locationTimezoneName = "location_timezone_name"
// case locationTimezoneCode = "location_timezone_code"
// case sortOrder = "sort_order"
// }
}
struct WorkEligibility: Decodable {
let work_eligibility_id: String?
let work_eligibility_name: String?
let work_eligibility_code: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
// case workEligibilityID = "work_eligibility_id"
// case workEligibilityName = "work_eligibility_name"
// case workEligibilityCode = "work_eligibility_code"
// case sortOrder = "sort_order"
// }
}
struct SeekingStatus: Decodable {
let seeking_status_id: String?
let seeking_status_name: String?
let seeking_status_code: String?
let sort_order: String?
// enum CodingKeys: String, CodingKey {
//
// case seekingStatusID = "seeking_status_id"
// case seekingStatusName = "seeking_status_name"
// case seekingStatusCode = "seeking_status_code"
// case sortOrder = "sort_order"
// }
}
struct DiscAdjData: Decodable {
let disc_adj_id: String?
let disc_adj_name: String?
let disc_adj_code: String?
// enum CodingKeys: String, CodingKey {
//
// case discAdjID = "disc_adj_id"
// case discAdjName = "disc_adj_name"
// case discAdjCode = "disc_adj_code"
// }
}
struct JSOccupation: Decodable {
let occupation_id: String?
let occupation_name: String?
let occupation_code: String?
let job_family_id: String?
let soc_coverage: String?
let description: String?
let education_level_id: String?
// enum CodingKeys: String, CodingKey {
// case occupationID = "occupation_id"
// case occupationName = "occupation_name"
// case occupationCode = "occupation_code"
// case jobFamilyID = "job_family_id"
// case socCoverage = "soc_coverage"
// case description = "description"
// case educationLevelID = "education_level_id"
// }
}
struct JSSearchPlaces: Decodable {
let geo_place_id: String?
let country_code: String?
let geo_place_code: String?
let geo_place_name: String?
// enum CodingKeys: String, CodingKey {
//
// case geoPlaceId = "geo_place_id"
// case countryCode = "country_code"
// case geoPlaceCode = "geo_place_code"
// case geoPlaceName = "geo_place_name"
// }
}
struct JSWorkTypes: Decodable {
let work_type_id: String?
let work_type_name: String?
// enum CodingKeys: String, CodingKey {
//
// case workTypeID = "work_type_id"
// case workTypeName = "work_type_name"
// }
}
After that, I made the request:
class JobSeekerJsonRequests: NSObject{
class func jobSeekerRequest(completion: #escaping(_ error: Error?, _ jobSeekerData : JobSeekerDataAPI?) ->Void) {
let jsonURLString = URLs.jobSeeker
guard let url = URL(string: jsonURLString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do {
let jobSeekerData = try
JSONDecoder().decode(JobSeekerDataAPI.self, from: data)
print(jobSeekerData)
}catch let jsonError {
print("Error serializing json: ", jsonError)
}
}.resume()
}
And then:
func userData(){
JobSeekerJsonRequests.jobSeekerRequest { (error: Error?, jobSeekerData: JobSeekerDataAPI?) in
if let jobSeekerData = jobSeekerData {
self.myProfileJobTitle.text = jobSeekerData.most_recent_work_history?.position
self.menuProfileName.text = jobSeekerData.job_seeker_name
self.userNameLabel.text = jobSeekerData.first_name
self.userNameJobPositionLabel.text = jobSeekerData.most_recent_work_history?.position
self.userLocationLabel.text = jobSeekerData.location_country?.location_country_name
self.infoAboutLabel.text = jobSeekerData.about
self.userJobTitleLabel.text = jobSeekerData.most_recent_work_history?.position
}
}
I have some problem to understand the API requests becuase I've been working on this and I didn't have any answer from that. I'm learning swift by myself this last 5 month and i'm stuck on this. Sorry If it looks like a stupid question but it's how new guys likes me stuck and need help.
Thank you guys!
The way you are using CodingKeys enum is not correct.
As stated in Apple docs:
The names of the enumeration cases should match the names you've given
to the corresponding properties in your type.
If the keys used in your serialized data format don't match the
property names from your data type, provide alternative keys by
specifying String as the raw-value type for the CodingKeys
enumeration. The string you use as a raw value for each enumeration
case is the key name used during encoding and decoding.
In short:
case name is exactly same as the property name
rawValue of a particular case is the custom key name that you want to use.
You are doing exact opposite of what needs to be done.
Example:
struct JobSeekerDataAPI : Decodable
{
let job_seeker_id: String?
let job_seeker_name: String?
//Other properties
enum CodingKeys: String, CodingKey
{
case job_seeker_id = "jobSeekerID" //case name is same as property name
case job_seeker_name = "jobseekerName"
//Other cases
}
}
For more clarification, refer to: https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
You need to do the same for all the structs that you want to be Decodable.
This will surely resolve your issue.
Edit: Getting nil after decoding the json response data
I you are getting nil, check what your API is returning in response. I have included a code snippet of what you API response should look like and what will you obtain as a result:
class JobSeekerJsonRequests: NSObject
{
class func jobSeekerRequest(completion: #escaping(_ error: Error?, _ jobSeekerData : JobSeekerDataAPI?) ->Void)
{
let jsonResponseString = "{\"jobSeekerID\":\"1234\",\"jobseekerName\":\"abcd\"}" //Something like this must be the format of your JSON response. Check the key names that are used here.
guard let data = jsonResponseString.data(using: .utf8) else {
return
}
do
{
let jobSeekerData = try
JSONDecoder().decode(JobSeekerDataAPI.self, from: data)
print(jobSeekerData)
}
catch let jsonError
{
print("Error serializing json: ", jsonError)
}
}
func userData()
{
//Your code
}
}
Output you will get after print(jobSeekerData) statement is executed:
JobSeekerDataAPI(job_seeker_id: Optional("1234"), job_seeker_name: Optional("abcd"))
Just make sure you use the correct key names, since your result completely depends on it.
Note: First test your code with less number of properties in struct so that debugging is easy. Adding more code make it difficult to debug the issue. So, start with small and then eventually make it big.
Let me know if you still face any issue.
You forgot to add CodingKeys for below in enum CodingKeys: String, CodingKey
let most_recent_work_history: WorkHistory?
let most_recent_education: EducationHistory?
Related
I am making a project in Swift with MVVM design. I want to get coin name, current price, Rank and Symbol from a Crypto site. I can't show the json data I get on the console. The model is in another folder because I did it with MVVM. How can I create a struct to get the data here? You can find screenshots of my project below. I would be glad if you help.
Below are the codes I wrote in my web service file
import Foundation
class WebService {
func downloadCurrencies(url: URL, completion: #escaping ([DataInfo]?) -> ()) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
completion(nil)
} else if let data = data {
let cryptoList = try? JSONDecoder().decode([DataInfo].self, from: data)
print(cryptoList)
if let cryptoList = cryptoList {
completion(cryptoList)
}
}
}
.resume()
}
}
Below are the codes I wrote in my model file
import Foundation
struct DataInfo : Decodable {
var name: String
var symbol: String
var cmc_rank: String
var usd: Double
}
Finally, here is the code I wrote to print the data in the viewController to my console. But unfortunately I can't pull the data.
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=10&convert=USD&CMC_PRO_API_KEY=5ac24b80-27a1-4d01-81bd-f19620533480")!
WebService().downloadCurrencies(url: url) { cryptos in
if let cryptos = cryptos {
print(cryptos)
}
}
}
I've seen your URL and tested it ON Postman and also i've got your code and tried to put it in a shape, the code is good, but it can't MAP JSON Data against your struct because this is the json Data from Postman
Postman Data
While Looking at your Struct, It Doesnt Match the format of JSON Data you're receiving,
Struct
Well, To Make your structure match the JSON String you need to create Nested String: Any Dictionary. But there's another issue with the logic, you need to decode data outside of the webservice call because it can contain errors which wont be mapped in the struct and can handle if you get other statusCode.
If you try to implement all these things manually, the code will become complex and hard to understand. I would rather recommend you to use Alamofire with SwiftyJSON and it can make your work a lot shorter and easier and understandable.
Sorry for the bad english.
Your api-key is not valid for me.
Your data must be inside of object or invalid keys and you are surely missing it thats why it is not parsing correctly.
My suggestion is to put your json response in this website
"https://app.quicktype.io/"
and replace your struct with new one, you will be good to go hopefully.
Your models does not have 1 to 1 correspondence with the response object. The root object is not a [DataInfo], but another structure that contains an array of DataInfos. Here are the correct models
struct Response: Codable {
let status: Status
let data: [CurrencyData]
}
struct Status: Codable {
let creditCount: Int
let elapsed: Int
let timestamp: String
let totalCount: Int
let errorCode: Int?
let errorMessage: String?
let notice: String?
enum CodingKeys: String, CodingKey {
case notice
case timestamp
case elapsed
case creditCount = "credit_count"
case errorCode = "error_code"
case errorMessage = "error_message"
case totalCount = "total_count"
}
}
enum Currency: String, Codable, Hashable {
case usd = "USD"
}
struct CurrencyData: Codable {
let circulatingSupply: Double?
let cmcRank: Int
let dateAdded: String?
let id: Int
let lastUpdated: String?
let maxSupply: Int?
let name: String
let numMarketPairs: Int
let platform: Platform?
let quote: [String: Price]
let selfReportedCirculatingSupply: String?
let selfReportedMarketCap: String?
let slug: String
let symbol: String
let tags: [String]?
let totalSupply: Double
func price(for currency: Currency) -> Double? {
return quote[currency.rawValue]?.price
}
enum CodingKeys: String, CodingKey {
case id
case name
case platform
case quote
case slug
case symbol
case tags
case circulatingSupply = "circulating_supply"
case cmcRank = "cmc_rank"
case dateAdded = "date_added"
case lastUpdated = "last_updated"
case maxSupply = "max_supply"
case selfReportedCirculatingSupply = "self_reported_circulating_supply"
case selfReportedMarketCap = "self_reported_market_cap"
case totalSupply = "total_supply"
case numMarketPairs = "num_market_pairs"
}
}
struct Price: Codable {
let fullyDilutedMarketCap: Double?
let lastUpdated: String?
let marketCap: Double?
let marketCapDominance: Double?
let percentChange1h: Double?
let percentChange24h: Double?
let percentChange30d: Double?
let percentChange60d: Double?
let percentChange7d: Double?
let percentChange90d: Double?
let price: Double?
let volume24h: Double?
let volumeChange24h: Double?
enum CodingKeys: String, CodingKey {
case price
case fullyDilutedMarketCap = "fully_diluted_market_cap"
case lastUpdated = "last_updated"
case marketCap = "market_cap"
case marketCapDominance = "market_cap_dominance"
case percentChange1h = "percent_change_1h"
case percentChange24h = "percent_change_24h"
case percentChange30d = "percent_change_30d"
case percentChange60d = "percent_change_60d"
case percentChange7d = "percent_change_7d"
case percentChange90d = "percent_change_90d"
case volume24h = "volume_24h"
case volumeChange24h = "volume_change_24h"
}
}
struct Platform: Codable {
let id: Int
let name: String
let symbol: String
let slug: String
let tokenAddress: String?
enum CodingKeys: String, CodingKey {
case id
case name
case symbol
case slug
case tokenAddress = "token_address"
}
}
and you can retrieve the cryptoList in your completion handler like this:
let cryptoList = (try? JSONDecoder().decode([Response].self, from: data))?.data
Also it's not safe to expose your personal data to the internet (API_KEY, etc.)
struct NewsModel: Codable{
let id: Int?
let title, newsModelDescription: String?
let sourceID, version: String?
let publishedAt: Int
let readablePublishedAt: String?
let updatedAt: Int
let readableUpdatedAt: String
let images: Images
let embedTypes: String?
let typeAttributes: TypeAttributes
let type: String?
let source: String?
enum CodingKeys: String, CodingKey {
case id, title
case newsModelDescription
case sourceID
case version, publishedAt, readablePublishedAt, updatedAt, readableUpdatedAt, embedTypes, images,typeAttributes, type, source
}
}
// MARK: - Images
struct Images: Codable {
let square140: String
enum CodingKeys: String, CodingKey {
case square140 = "square_140"
}
}
struct TypeAttributes: Codable {
let imageLarge: String
}
This is my Model. I can successfully parse them and show them on UITableViewCell but I am unable to save them to the realm because these are struct. For save to realm I need to convert them to class and Realm object. But how I convert them to nested class. I want to use the same model to parse and saving data to the realm is it possible?
There are probably 100 different solutions. One option is to just make the object a Realm object that's conforms to the codable protocol. Something like this (not tested: so more of a conceptual solution)
class NewsModel: Object, Codable {
#objc dynamic var _id = UUID().uuidString
#objc dynamic var title = ""
#objc dynamic var news = ""
private enum CodingKeys: String, CodingKey {
case _id
case title
case news
}
override class func primaryKey() -> String? {
return "_id"
}
public required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
self._id = try container.decode(String.self, forKey: ._id)
self.name = try container.decode(String.self, forKey: .title)
self.logo = try container.decode(String.self, forKey: .news)
}
or change the model in the question to a class and add a function to save a realm object with the data. Again, not tested so this is just conceptual.
class RealmNewsModel: Object {
#objc dynamic var _id = ""
#objc dynamic var title = ""
#objc dynamic var news = ""
}
class NewsModel, Codable {
let _id: String?
let title: String?
let news: String?
func saveToRealm {
let news = RealmNewsModel()
news._id = self._id
news.title = self.title
news.news = self.news
try! realm.write {
realm.add(news)
}
I have decoded this using JSONSerialization. But for my own knowledge and the maintenance of my code. I would like to know how to decode this.
This is what I have so far:
let urlString = "site deleted" + "/DataSource/Mobile/?Action=MyProfile&uid=" + uid + "&uuid=" + uuid
guard let url = URL(string: urlString) else {return}
URLSession.shared.dataTask(with: url) { (data, _, error) in
if let err = error {
print("Handle MyProfileJSON error: ", err)
}
guard let data = data else {return}
do {
// swift 4.2 but we cant use it right now
let profile = try JSONDecoder().decode(RequestResult.self, from: data)
print(profile)
completion(profile)
} catch let err {
print("Handle Decoder Error: ", err)
}
}.resume()
I'm not too worried about the cases but this is what I have so far. I know the case I use is not the convention, that's why I did this with JSONSerialization so I can use camelCase. If you can help me convert it to camelCase too that would be amazing but my focus is to Decode this using Decodable class. Thanks a lot, guys.
And this are my structs:
struct RequestResult: Decodable {
var Action: String?
var Params: [String: String]?
var DATA: [String: String]?
}
struct Params: Decodable {
var Action_get: String?
var uid_get: String?
}
struct DATA: Decodable {
var Id: String?
var UserCode: String?
var HomePhone: String?
var Mobile: String?
var WorkPhone: String?
var Email: String?
var AltEmail: String?
var UnitNo: String?
var StreetNo: String?
var StreetName: String?
var City: String?
var StateProvince: String?
var Country: String?
var ZipPostalCode: String?
}
The structure of the JSON is very clear
The root object RequestResult contains a string and two dictionaries.
The dictionaries are replaced by structs.
The CodingKeys are useful to rename the keys to more meaningful and naming convention conforming names. The left side of an enum case is the struct member name, the right side the original JSON key.
A struct member name must match the dictionary key (or the mapped CodingKey).
The struct names are arbitrary.
All struct members can be declared as constants (let) and as non-optional if the JSON contain always the keys.
struct RequestResult: Decodable {
private enum CodingKeys : String, CodingKey {
case action = "Action", params = "Params", data = "DATA"
}
let action: String
let params: Parameter
let data: UserData
}
The dictionary for key Params will be renamed to Parameter and DATA to UserData
struct Parameter: Decodable {
private enum CodingKeys : String, CodingKey {
case action = "Action_get", uid = "uid_get"
}
let action: String
let get: String
}
struct UserData: Decodable {
private enum CodingKeys : String, CodingKey {
case id = "Id", userCode = "UserCode", homePhone = "HomePhone"
case mobile = "Mobile", workPhone = "WorkPhone", email = "Email"
case altEmail = "AltEmail", unitNo = "UnitNo", streetNo = "StreetNo"
case streetName = "StreetName", city = "City", stateProvince = "StateProvince"
case country = "Country", zipPostalCode = "ZipPostalCode"
}
let id: String, userCode, homePhone, mobile: String
let workPhone, email, altEmail, unitNo: String
let streetNo, streetName, city, stateProvince: String
let country, zipPostalCode: String
}
I need to parse a json with a game instruction, but in the backend they change the param previously in Int to a Float (IDK why, but now is like that)
this is the error
Unexpected error: dataCorrupted(Swift.DecodingError.Context(codingPath: [ios_apps.HomeResponse.(CodingKeys in _B9BDF2CE76592A42518B3A0888B1E0F5).game, ios_apps.Game.(CodingKeys in _BAE470AF8C81659CF18E4A8D481877B9).counterLeft], debugDescription: "Parsed JSON number <53422.434> does not fit in Int.", underlyingError: nil)).
and this is the struct
import Foundation
struct Game : Decodable {
let gameId : String?
let currentTime : String?
let counterLeft : Int?
let counterStart : String?
let counterStep : String?
let gameEnd : String?
let gameIntroduction : String?
let gamePlay : Bool?
let gameStart : String?
let gameType : String?
let gameUserPlayed : Bool?
let picture : String?
let started : Bool?
// private var counterLeft : Float?
}
struct CounterLeft: Codable, Loopable {
let counterLeft : Int?
enum CodingKeys: String, CodingKey {
case counterLeft = "counterLeft"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
counterLeft = try Int(values.decode(Float.self, forKey: .counterLeft))
}
}
the response form json
game = {
counterLeft = "53422.434";
counterStart = "2018-03-26T07:00:00.000Z";
counterStep = countDown;
currentTime = "2018-03-26T21:09:37.562Z";
gameEnd = "2018-03-28T15:00:51.000Z";
gameId = 5ab906957889034b223b3ba4;
gameIntroduction = "Lorem Ipsum";
gamePlay = 0;
gameStart = "2018-03-27T12:00:00.000Z";
gameType = spinwheel;
gameUserPlayed = 0;
picture = "/files/1522075335538L.png";
started = 1;
};
I need the counterLeft to be in Int for countdown reasons
Use Double. I run a simple model of your test data, it is working.
Here is the code in swift 4:
var json = """
{
"counterLeft" : 53422.434,
"counterStart" : "2018-03-26T07:00:00.000Z"
}
""".data(using: .utf8)
struct model : Codable {
let counterLeft : Int?
let counterStart : String?
enum CodingKeys: String, CodingKey {
case counterLeft = "counterLeft"
case counterStart = "counterStart"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
counterLeft = try Int(values.decodeIfPresent(Double.self, forKey: .counterLeft) ?? 0)
counterStart = try values.decodeIfPresent(String.self, forKey: .counterStart)
}
}
let responseModel = try JSONDecoder().decode(model.self, from: json!)
I'm pretty stuck now. I'm attempting to PARS a JSON RETURN for just the year make make and model. It's buried in an array of dictionaries, and the decoder is having a hard time pulling them out. What am I doing wrong?
public struct Page: Decodable {
let Count: Int
let Message: String
let SearchCriteria: String
let Results: [car]}
public struct car: Decodable {
let ModelYear: String
let Make: String
let Model: String
let VIN: String}
let session = URLSession.shared
let components = NSURLComponents()
components.scheme = "https"
components.host = "vpic.nhtsa.dot.gov"
components.path = "/api/vehicles/decodevinvaluesextended/\(VIN)"
components.queryItems = [NSURLQueryItem]() as [URLQueryItem]
let queryItem1 = NSURLQueryItem(name: "Format", value: "json")
components.queryItems!.append(queryItem1 as URLQueryItem)
print(components.url!)
let task = session.dataTask(with: components.url!, completionHandler: {(data, response, error) in
guard let data = data else { return }
do
{
//let Result = try JSONDecoder().decode(Page.self, from: data)
// let PageResult = try JSONDecoder().decode(Page.self, from: data)
let json = try JSONDecoder().decode(Page.self, from: data)
let Results = json.Results;
print(Results)
First of all it's highly recommended to conform to the Swift naming convention that variable names start with a lowercase and structs start with a capital letter
public struct Page: Decodable {
private enum CodingKeys : String, CodingKey {
case count = "Count", message = "Message", searchCriteria = "SearchCriteria", cars = "Results"
}
let count: Int
let message: String
let searchCriteria: String
let cars: [Car]
}
public struct Car: Decodable {
private enum CodingKeys : String, CodingKey {
case modelYear = "ModelYear", make = "Make", model = "Model", VIN
}
let modelYear: String
let make: String
let model: String
let VIN: String
}
The cars array is in the variable result. This code prints all values
let result = try JSONDecoder().decode(Page.self, from: data)
for car in result.cars {
print("Make: \(car.make), model: \(car.model), year: \(car.modelYear), VIN: \(car.VIN)")
}