Swift Higher Order Functions, Codable, Model Creation, Nested JSON
Parsing Imgur json.
How would you assign 'title' from ImageData to Image's title ? Is there a way using higher order functions?
struct ImgurResponse: Codable {
let data: [ImageData]
}
struct ImageData: Codable {
let title: String
let images: [Image]
}
struct Image: Codable {
let title, descripton, nsfw: String
let link: String
}
User @Dhawal suggested adding following init to Image:
init(title: String, desc: String, nsfw: String, link: String) {
self.title = title
self.description = desc
self.nsfw = nsfw
self.link = link
so that we can:
let response = try JSONDecoder().decode(ImgurResponse.self, from: data)
let images = response.data.compactMap{Image(title: $0.title, desc: $0.images.first!.description, nsfw: $0.images.first!.nsfw, link: $0.images.first!.link)}
Anything more swifty then that?
See also questions close to this topic
-
JSONDecodeError when using for loop in python
I've been trying to do some API queries to get some missing data in my DF. I'm using grequest library to send multiple request and create a list for the response object. Then I use a for loop to load the response in a json to retrieve the missing data. What I noticed is that when loading the data using .json() from the list directly using notition list[0].json() it works fine, but when trying to read the list and then load the response into a json, This error comes up : JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Here's my code :
import requests import json import grequests ls = [] for i in null_data['name']: url = 'https://pokeapi.co/api/v2/pokemon/' + i.lower() ls.append(url) rs = (grequests.get(u) for u in ls) s = grequests.map(rs) #This line works print(s[0].json()['weight']/10) for x in s: #This one fails js = x.json() peso = js['weight']/10 null_data.loc[null_data['name'] == i.capitalize(), 'weight_kg'] = peso
<ipython-input-21-9f404bc56f66> in <module> 13 14 for x in s: ---> 15 js = x.json() 16 peso = js['weight']/10 17 null_data.loc[null_data['name'] == i.capitalize(), 'weight_kg'] = peso JSONDecodeError: Expecting value: line 1 column 1 (char 0)
-
How i can read the nested properties and pushing to the array using javascript?
I want to read the JSON properties. if type is array or object or jsonp then i have to read the nested properties and need push it one array which should also be nested. like:
{ name:"test", type:"array" [name]: { name: "test1", type: "..." } }
JSON object to read:
{ "properties": { "value": { "type": "array", "items": { "required": [ "@odata.etag", "id", "createdDateTime", "lastModifiedDateTime", "changeKey", "originalStartTimeZone", "originalEndTimeZone", "iCalUId", "reminderMinutesBeforeStart", "isReminderOn", "hasAttachments", "subject", "bodyPreview", "importance", "sensitivity", "isAllDay", "isCancelled", "isOrganizer", "responseRequested", "showAs", "type", "webLink", "isOnlineMeeting", "onlineMeetingProvider", "allowNewTimeProposals", "isDraft", "hideAttendees" ], "properties": { "id": { "type": "string", "minLength": 1 }, "end": { "type": "object", "required": [ "dateTime", "timeZone" ], "properties": { "dateTime": { "type": "string", "minLength": 1 }, "timeZone": { "type": "string", "minLength": 1 } } }, "body": { "type": "object", "required": [ "contentType", "content" ], "properties": { "content": { "type": "string", "minLength": 1 }, "contentType": { "type": "string", "minLength": 1 } } }, "type": { "type": "string", "minLength": 1 }, "start": { "type": "object", "required": [ "dateTime", "timeZone" ], "properties": { "dateTime": { "type": "string", "minLength": 1 }, "timeZone": { "type": "string", "minLength": 1 } } }, "showAs": { "type": "string", "minLength": 1 }, "iCalUId": { "type": "string", "minLength": 1 }, "isDraft": { "type": "boolean" }, "subject": { "type": "string", "minLength": 1 }, "webLink": { "type": "string", "minLength": 1 }, "isAllDay": { "type": "boolean" }, "location": { "type": "object", "required": [ "displayName", "locationType", "uniqueIdType", "address", "coordinates" ], "properties": { "address": { "type": "object", "required": [], "properties": {} }, "coordinates": { "type": "object", "required": [], "properties": {} }, "displayName": { "type": "string" }, "locationType": { "type": "string", "minLength": 1 }, "uniqueIdType": { "type": "string", "minLength": 1 } } }, "attendees": { "type": "array", "items": { "required": [ "type" ], "properties": { "type": { "type": "string", "minLength": 1 }, "status": { "type": "object", "required": [ "response", "time" ], "properties": { "time": { "type": "string", "minLength": 1 }, "response": { "type": "string", "minLength": 1 } } }, "emailAddress": { "type": "object", "required": [ "name", "address" ], "properties": { "name": { "type": "string", "minLength": 1 }, "address": { "type": "string", "minLength": 1 } } } } }, "minItems": 1, "uniqueItems": true }, "changeKey": { "type": "string", "minLength": 1 }, "locations": { "type": "array", "items": { "required": [], "properties": {} } }, "organizer": { "type": "object", "required": [ "emailAddress" ], "properties": { "emailAddress": { "type": "object", "required": [ "name", "address" ], "properties": { "name": { "type": "string", "minLength": 1 }, "address": { "type": "string", "minLength": 1 } } } } }, "categories": { "type": "array", "items": { "required": [], "properties": {} } }, "importance": { "type": "string", "minLength": 1 }, "recurrence": {}, "@odata.etag": { "type": "string", "minLength": 1 }, "bodyPreview": { "type": "string", "minLength": 1 }, "isCancelled": { "type": "boolean" }, "isOrganizer": { "type": "boolean" }, "sensitivity": { "type": "string", "minLength": 1 }, "isReminderOn": { "type": "boolean" }, "hideAttendees": { "type": "boolean" }, "onlineMeeting": {}, "transactionId": {}, "hasAttachments": { "type": "boolean" }, "responseStatus": { "type": "object", "required": [ "response", "time" ], "properties": { "time": { "type": "string", "minLength": 1 }, "response": { "type": "string", "minLength": 1 } } }, "seriesMasterId": {}, "createdDateTime": { "type": "string", "minLength": 1 }, "isOnlineMeeting": { "type": "boolean" }, "onlineMeetingUrl": {}, "responseRequested": { "type": "boolean" }, "originalEndTimeZone": { "type": "string", "minLength": 1 }, "lastModifiedDateTime": { "type": "string", "minLength": 1 }, "allowNewTimeProposals": { "type": "boolean" }, "onlineMeetingProvider": { "type": "string", "minLength": 1 }, "originalStartTimeZone": { "type": "string", "minLength": 1 }, "reminderMinutesBeforeStart": { "type": "number" } } }, "minItems": 1, "uniqueItems": true }, "@odata.context": { "type": "string", "minLength": 1 }, "@odata.nextLink": { "type": "string", "minLength": 1 } } }
-
Using Jackson to deserialize with Lombok builder
The Question
Lombok's
@builder
annotation creates a builder-class for a class. To support deserialization of json items (using Jackson's ObjectMapper), I've added the following annotations:@Builder @JsonDeserialize(builder = Item.ItemBuilder.class) @JsonPOJOBuilder(withPrefix="") public class Item { @Getter String partitionvalue; }
This is based on the
@Jacksonized
documentation. On the usage of the deserializer, upon a json file which is stored in AWS S3 bucket and its content is simply:{"partitionvalue": "test"}
, my code is:AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withCredentials(new DefaultAWSCredentialsProviderChain()) .withRegion(region) .build(); S3Object s3Object = s3Client.getObject(new GetObjectRequest(bucket, key)); Item item = objectMapper.readValue(s3Object.getObjectContent(), Item.class);
However when running on a json file that Jackson fails with the message:
Unrecognized field "partitionvalue" (class com.example.Test$TestBuilder), not marked as ignorable (0 known properties: ]) at [Source: com.amazonaws.services.s3.model.S3ObjectInputStream@2ca47471; line: 1, column: 21] (through reference chain: com.example.TestBuilder["partitionvalue"])
Extra Details
Using @
Jacksonized
annotation directly didn't work as well, and since it is lombok-experimental I used the annotations I needed to use with builder directly.I verified that Lombok will do what I expect of a builder class by using "delombok" option in the Lombok IntelliJ plugin:
public class Item { String partitionvalue; Item(String partitionvalue) { this.partitionvalue = partitionvalue; } public static ItemBuilder builder() { return new ItemBuilder(); } public String getPartitionvalue() { return this.partitionvalue; } public static class ItemBuilder { private String partitionvalue; ItemBuilder() { } public Item.ItemBuilder partitionvalue(String partitionvalue) { this.partitionvalue = partitionvalue; return this; } public Item build() { return new Item(partitionvalue); } public String toString() { return "Item.ItemBuilder(partitionvalue=" + this.partitionvalue + ")"; } } }
- Without the
@Builder
annotation (and with adding@NoArgsConstructor
+@AllArgsConstructor
+@Setter
) it worked fine, so the problem isn't with the file from the S3 bucket or the way it is parsed.
-
Swift - How can we change view controller with remote config
I have 2 view controllers. I want to change the view controller like changing the label with remote config. How can I do this? I don't have to do it with remote config, but how can I change the view controller remotely.
-
Cannot find 'WeatherManager' in scope
I am new to swift and this is my first question here.
I tried creating a new file in the models and renaming it but that didn't work. It shows the same error. I tried clearing the build folder(shift+ command + k) and restarting my mac. I have gone through a few answers here but none of them worked. Any help will be highly appreciated.
-
Find MAC address of IoT device connected to Wi-Fi
We need to get MAC address of IoT (Base Station/Smart Hub) device connected to our Wi-Fi. We are able to get device list, their ip addresses, and Wi-Fi SSID and BSSID currently connected but we are not able to get MAC Address of devices.
Our requirement is to get all devices and then filter out our IoT device by Mac address regex and then pass that Mac address to API for further communication.
We are aware that Apple has stopped MAC address API since iOS 11 but still Fing app is able to find MAC addresses.
We have tried out all the related answers for this issue:
- How does iOS app Fing get MAC Address?
- Getting ARP table on iPhone/iPad
- Library: https://github.com/mavris/MMLanScan
So, is there any way we can get MAC address by using any service or requesting to Apple for enabling access?
-
Native Ad not open on tap iOS
I'm using Mobile Ads SDK (iOS) to show native ads which shows it perfectly fine but my main issue not being clickable inside a custom UITableView Cell. I'm using a cell from a xib.
My cell view hierarchy is the following.
And the code to show the native ad in
cellForRowAtIndexpath
:case CardType.ad.rawValue: guard let cell = tableView.dequeueReusableCell(withIdentifier: "NativeTableViewCell") as? NativeTableViewCell else { return UITableViewCell() } guard let nativeAd = nativeAD else { return UITableViewCell() } nativeAd.rootViewController = self cell.setupAd(nativeAd) guard let adView = cell.contentView.subviews.first as? GADUnifiedNativeAdView else { return UITableViewCell() } adView.callToActionView?.isUserInteractionEnabled = false adView.nativeAd = nativeAd return cell
where the native ad is var
nativeAD: GADUnifiedNativeAd?
where I'm assigning it in the delegate methodfunc adLoader(_: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd) { nativeAD = nativeAd
}
Did anyone else encounter this kind of issue?. Any help is appreciated.
-
Swift - Problem with scrollview (Need to print when dragging down)
I am testing the swiping controller/gesture from Jake Spracher with his SnapchatSwipeView (https://github.com/jakespracher/Snapchat-Swipe-View )
I have setup a topVC,leftVC,rightVC and middleVC(the main VC).
I manage to capture when the user swipe from the center to the rightVC or to the left VC, with this :
func scrollViewDidScroll(_ scrollView: UIScrollView) { if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled { let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y) self.scrollView!.setContentOffset(newOffset, animated: false) } if (scrollView.contentOffset) == CGPoint(x: 750.0, y: 0.0) { print ("TEST OK LEFT!") NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadRinkbox"), object: nil) } if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) { print ("TEST OK LEFT!") } if (scrollView.contentOffset) == CGPoint(x: -750.0, y: 0.0) { print ("TEST OK RIGHT") } if (scrollView.contentOffset) == CGPoint(x: 375, y: 0.0) { print ("TEST OK!") } }
But I cannot manage to capture when the user swipe from the centerVC to the topVC, and from topVC to centerVC. I have tried a lot of things but I didn't manage to do it.
My code is for swift 4.
For clarity, I put here the two full swift files. Many, million thanks for those that can help me !
ContainerViewController.swift
// // ContainerViewController.swift // SnapchatSwipeView // // Created by Jake Spracher on 8/9/15. // Copyright (c) 2015 Jake Spracher. All rights reserved. // import UIKit import AVFoundation protocol SnapContainerViewControllerDelegate { // print "Snapcontainerview" func outerScrollViewShouldScroll() -> Bool } class SnapContainerViewController: UIViewController, UIScrollViewDelegate { var captureSession : AVCaptureSession! private var current: UIViewController // print "2" var deeplink: DeeplinkType? { didSet { handleDeeplink() } } init() { current = SplashViewController() super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } var topVc: UIViewController? var leftVc: UIViewController! var middleVc: UIViewController! var rightVc: UIViewController! var bottomVc: UIViewController? var directionLockDisabled: Bool! var horizontalViews = [UIViewController]() var veritcalViews = [UIViewController]() var initialContentOffset = CGPoint() // scrollView initial offset var middleVertScrollVc: VerticalScrollViewController! var scrollView: UIScrollView! var delegate: SnapContainerViewControllerDelegate? class func containerViewWith(_ leftVC: UIViewController, middleVC: UIViewController, rightVC: UIViewController, topVC: UIViewController?=nil, bottomVC: UIViewController?=nil, directionLockDisabled: Bool?=false) -> SnapContainerViewController { let container = SnapContainerViewController() container.directionLockDisabled = directionLockDisabled container.topVc = topVC container.leftVc = leftVC container.middleVc = middleVC container.rightVc = rightVC container.bottomVc = bottomVC return container } var scrollOffSetClosure: ((_ offset: CGFloat) -> Void)? // code truncated for brevity func scrollViewDidScroll2(_ scrollView: UIScrollView) { scrollOffSetClosure!(scrollView.contentOffset.x) print("test here") } func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { print("end scroll") } override func viewDidLoad() { super.viewDidLoad() addChildViewController(current) current.view.frame = view.bounds view.addSubview(current.view) current.didMove(toParentViewController: self) } func setupVerticalScrollView() { middleVertScrollVc = VerticalScrollViewController.verticalScrollVcWith(middleVc: middleVc as! Camera, topVc: topVc, bottomVc: bottomVc) delegate = middleVertScrollVc } func setupHorizontalScrollView() { scrollView = UIScrollView() scrollView.isPagingEnabled = true scrollView.showsHorizontalScrollIndicator = false scrollView.bounces = false print ("6") let view = ( x: self.view.bounds.origin.x, y: self.view.bounds.origin.y, width: self.view.bounds.width, height: self.view.bounds.height ) scrollView.frame = CGRect(x: view.x, y: view.y, width: view.width, height: view.height ) self.view.addSubview(scrollView) let scrollWidth = 3 * view.width let scrollHeight = view.height scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight) leftVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height ) middleVertScrollVc.view.frame = CGRect(x: view.width, y: 0, width: view.width, height: view.height ) rightVc.view.frame = CGRect(x: 2 * view.width, y: 0, width: view.width, height: view.height ) addChildViewController(leftVc) addChildViewController(middleVertScrollVc) addChildViewController(rightVc) scrollView.addSubview(leftVc.view) scrollView.addSubview(middleVertScrollVc.view) scrollView.addSubview(rightVc.view) leftVc.didMove(toParentViewController: self) middleVertScrollVc.didMove(toParentViewController: self) rightVc.didMove(toParentViewController: self) scrollView.contentOffset.x = middleVertScrollVc.view.frame.origin.x scrollView.delegate = self } func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { // print ("Scrollviewvillbegindragging scrollView.contentOffset \(scrollView.contentOffset)") self.initialContentOffset = scrollView.contentOffset } func scrollViewDidScroll(_ scrollView: UIScrollView) { if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled { let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y) // print(newOffset.x) //print(newOffset.y) // Setting the new offset to the scrollView makes it behave like a proper // directional lock, that allows you to scroll in only one direction at any given time self.scrollView!.setContentOffset(newOffset, animated: false) // print ("newOffset \(newOffset)") // tell child views they have appeared / disappeared } if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("aaa!")} if (scrollView.contentOffset) == CGPoint(x: 0.0, y: -667.0) {print ("bbb!")} if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 375) {print ("aaccca!")} if (scrollView.contentOffset) == CGPoint(x: 0.0, y: -375) {print ("ddddd!")} if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {print ("eeeeeee!")} // if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("ffffff!")} // if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("aggggggggaa!")} // print ("scrollViewDidScroll scrollView.contentOffset \(scrollView.contentOffset)") // scrollView.contentOffset if (scrollView.contentOffset) == CGPoint(x: 750.0, y: 0.0) { print ("TEST OK LEFT!") NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadRinkbox"), object: nil) } if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) { print ("TEST OK RIGHT!") } if (scrollView.contentOffset) == CGPoint(x: -750.0, y: 0.0) { print ("TEST OK LEFT") } if (scrollView.contentOffset) == CGPoint(x: 375, y: 0.0) { print ("TEST LEFT/RIGHT OK!") } } private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) { print ("Ca va dans animateFadeTransition") current.willMove(toParentViewController: nil) addChildViewController(new) transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: { }) { completed in self.current.removeFromParentViewController() new.didMove(toParentViewController: self) self.current = new completion?() } } private func animateDismissTransition(to new: UIViewController, completion: (() -> Void)? = nil) { print ("Ca va dans animateDismissTransition") let initialFrame = CGRect(x: -view.bounds.width, y: 0, width: view.bounds.width, height: view.bounds.height) current.willMove(toParentViewController: nil) addChildViewController(new) new.view.frame = initialFrame transition(from: current, to: new, duration: 0.3, options: [], animations: { new.view.frame = self.view.bounds }) { completed in self.current.removeFromParentViewController() new.didMove(toParentViewController: self) self.current = new completion?() } } }
and VerticalScrollViewController
/ MiddleScrollViewController.swift // SnapchatSwipeView // // Created by Jake Spracher on 12/14/15. // Copyright © 2015 Jake Spracher. All rights reserved. // import UIKit class VerticalScrollViewController: UIViewController, SnapContainerViewControllerDelegate { var topVc: UIViewController! var middleVc: UIViewController! var bottomVc: UIViewController! var scrollView: UIScrollView! class func verticalScrollVcWith(middleVc: UIViewController, topVc: UIViewController?=nil, bottomVc: UIViewController?=nil) -> VerticalScrollViewController { let middleScrollVc = VerticalScrollViewController() middleScrollVc.topVc = topVc middleScrollVc.middleVc = middleVc middleScrollVc.bottomVc = bottomVc return middleScrollVc } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view: setupScrollView() } func setupScrollView() { scrollView = UIScrollView() scrollView.isPagingEnabled = true scrollView.showsVerticalScrollIndicator = false scrollView.bounces = false let view = ( x: self.view.bounds.origin.x, y: self.view.bounds.origin.y, width: self.view.bounds.width, height: self.view.bounds.height ) scrollView.frame = CGRect(x: view.x, y: view.y, width: view.width, height: view.height) self.view.addSubview(scrollView) let scrollWidth: CGFloat = view.width var scrollHeight: CGFloat switch (topVc, bottomVc) { case (nil, nil): scrollHeight = view.height middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) addChildViewController(middleVc) scrollView.addSubview(middleVc.view) middleVc.didMove(toParentViewController: self) case (_?, nil): scrollHeight = 2 * view.height topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height) addChildViewController(topVc) addChildViewController(middleVc) scrollView.addSubview(topVc.view) scrollView.addSubview(middleVc.view) topVc.didMove(toParentViewController: self) middleVc.didMove(toParentViewController: self) scrollView.contentOffset.y = middleVc.view.frame.origin.y case (nil, _?): scrollHeight = 2 * view.height middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) bottomVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height) addChildViewController(middleVc) addChildViewController(bottomVc) scrollView.addSubview(middleVc.view) scrollView.addSubview(bottomVc.view) middleVc.didMove(toParentViewController: self) bottomVc.didMove(toParentViewController: self) scrollView.contentOffset.y = 0 default: scrollHeight = 3 * view.height topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height) bottomVc.view.frame = CGRect(x: 0, y: 2 * view.height, width: view.width, height: view.height) addChildViewController(topVc) addChildViewController(middleVc) addChildViewController(bottomVc) scrollView.addSubview(topVc.view) scrollView.addSubview(middleVc.view) scrollView.addSubview(bottomVc.view) topVc.didMove(toParentViewController: self) middleVc.didMove(toParentViewController: self) bottomVc.didMove(toParentViewController: self) scrollView.contentOffset.y = middleVc.view.frame.origin.y } scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight) } // MARK: - SnapContainerViewControllerDelegate Methods func outerScrollViewShouldScroll() -> Bool { if scrollView.contentOffset.y < middleVc.view.frame.origin.y || scrollView.contentOffset.y > 2*middleVc.view.frame.origin.y { return false } else { return true } } }
-
Safe JSON Decoding. Still getting Key not found: No value associated with key'
IMGUR image search returns json:
{"data": [{ "title": "Family :)", "images": [{ "title": null, "description": null, "nsfw": null, "link": "https:\/\/i.imgur.com\/oe5BrCu.jpg", }] } ] }
Model Object is configured:
struct ImgurResponse: Codable { let data: [ImageData] } struct ImageData: Codable { let title: String let images: [Image] } struct Image: Codable { let title, description, nsfw: String let link: String enum CodingKeys: String, CodingKey { case title case description case nsfw case link } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) title = try container.decodeIfPresent(String.self, forKey: .title) ?? "" description = try container.decodeIfPresent(String.self, forKey: .description) ?? "" nsfw = try container.decodeIfPresent(String.self, forKey: .nsfw) ?? "" link = try container.decodeIfPresent(String.self, forKey: .link) ?? "" }
Calling JSONDecoder():
let response = try JSONDecoder().decode(ImgurResponse.self, from: data)
When putting a brake point on the last line 'link = ' I land on it about 48 times. As i understand, we are able to create Image object 48 times.
Yet, im getting an error and 'response' isn't created:
Key 'CodingKeys(stringValue: "images", intValue: nil)' not found: No value associated with key CodingKeys(stringValue: "images", intValue: nil) ("images"). codingPath: [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 49", intValue: 49)]
What other 'safe' decoding practices should I implement?
-
Swift Codable: Decoding dynamic keys
I'm trying to practice Swift's Codable API. I send a network request and I receive one single line each time as follows where I have to deal with dynamic keys :
Response example 1:
{ "EUR": 4695.01 }
Response example 2:
{ "USD": 479.01 }
Response example 3:
{ "BTC": 4735.01 }
I tried this method to parse the dynamic keys :
struct ConversionResponseModel: Decodable { typealias destinationCurrency = String init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() } }
and my fetching request :
do { let myResult = try JSONDecoder().decode(ConversionResponseModel.self, from: data) print(myResult) } catch { print(error) }
But I get this as a result :
ConversionResponseModel()
, but not the currency values. It sounds like I'm missing something. Any help please. Thank you