I am getting data in [Any] format and I want to convert data into the format mentioned below
struct Details {
var image: UIImage?
var title: String?
var subTitle: String?
}
Related
This question already has answers here:
Have a variable with multiple types in Swift
(4 answers)
What is the Swift equivalent of a Typescript union type?
(2 answers)
Closed 14 days ago.
I have a 2 structs like so:
struct StructA: Codable {
let title: String?
let subtitle: String?
let myImage: URL?
}
struct StructB: Codable {
let title: String?
let subtitle: String?
let myImage: UIImage?
}
Now, in StructA, the variable myImage is of type URL? and in StructB the variable myImage is of type UIImage?. I want the variable myImage to be able to have either URL? or UIImage? as the type so that I can have a single struct instead of two. Can someone help?
I tried to use Generics on the struct so that I can assign structs of different type to the same variable..but couldn't achieve that.
If you want a single instance to be able to contain either a URL or a UIImage, you need to use an enum
struct StructAorB: Codable {
enum ImageKind: Codable
{
case url(URL)
case image(UIImage) // NB UIImage is not Codable, but this is irrelevant to the question
// You'll just need to extend it to conform
case none
}
let title: String?
let subtitle: String?
let myImage: ImageKind
}
If you find it inconvenient to have switches everywhere, create convenience properties
extension StructAorB
{
var imageAsUrl: URL?
{
switch myImage
{
case .url(let ret):
return ret
default:
return nil
}
}
}
my goal is to decode a deeply nested json response from an api and render it in a list, below is the raw response data and my attempt.
The problem is that when I attempt to initialize my data to then further populated when I make my API call it gives me an error
“ Listing(data: []) { ERROR: No exact matches in call to initializer”
Is this the correct way to declare my structs to decode a deeply nested JSON Object?
Api response data ->
https://pastebin.com/7pgswZqk
import Foundation
import SwiftUI
import Combine
struct Listing: Decodable {
var kind: String
struct data: Decodable {
var modhash: String
var dist: Int
struct children: Decodable {
var kind: String
struct data: Decodable { <--- this level is where my iterable children are
var title: String
... <---- there is more properties here but I just put title for now
}
}
}
}
class NetworkingManager : ObservableObject {
var didChange = PassthroughSubject<NetworkingManager, Never>()
var ListingList = Listing(data: []) { *ERROR: No exact matches in call to initializer*
didSet {
didChange.send(self)
}
}
init() {
guard let url = URL(string: "https://www.reddit.com/best.json?limit=25") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
guard let data = data else { return }
let List = try! JSONDecoder().decode(Listing.self, from: data)
DispatchQueue.main.async {
self.ListingList = List
}
}.resume()
}
}
Then to iterate over the list, would it be like this?
List(ListingList.data.children.data.identified(by ./title) {listItem in
Text(listItem.title)
}
You defined your custom Decodable nested structs but missing their application.
Your Listing should look something like this...
struct Listing: Decodable {
var kind: String
var data: Data // instance of custom Listing.Data struct
struct Data: Decodable { // your custom decodable struct
var modhash: String
var dist: Int
var children: [Children] // instance of your custom Listing.Data.Children struct
struct Children: Decodable { // your custom decodable struct
var kind: String
var data: Data
struct Data: Decodable {
var title: String
// ...
}
}
}
}
...but it becomes unreadable very quickly so better create separate structs instead of nesting. In the following example you can see that naming can become kindof tedious when having deeply nested responses.
struct Listing: Decodable {
var kind: String
var data: ListingData
}
struct ListingData: Decodable {
var modhash: String
var dist: Int
var children: [ListingDataChildren]
}
struct ListingDataChildren: Decodable {
var kind: String
var data: ListingDataChildrenData
}
struct ListingDataChildrenData: Decodable {
var title: String
// ...
}
The optimal solution would be to create extensions to still have that kind of hierarchy that you get via nesting.
struct Listing: Decodable {
var kind: String
var data: Data
}
extension Listing {
struct Data: Decodable {
var modhash: String
var dist: Int
var children: [Children]
}
}
extension Listing.Data {
struct Children: Decodable {
var kind: String
var data: Data
}
}
extension Listing.Data.Children {
struct Data: Decodable {
var title: String
// ...
}
}
I am trying to decode a JSON response from the youtube API in swift.
The JSON information is:
I made a Decodable structure:
// Build a model object to import the JSON data.
struct PlaylistInformation: Decodable {
struct Items: Decodable {
struct VideoNumber: Decodable {
struct Snippet: Decodable {
let title: String
}
let snippet: Snippet
}
let videoNumber: VideoNumber
}
let items: Items
}
And I get the error when trying to decode:
// We decode the JSON data get from the url according to the structure we declared above.
guard let playlistInformation = try? JSONDecoder().decode(PlaylistInformation.self, from: data!) else {
print("Error: could not decode data into struct") <-- HERE IS THE ERROR
return
}
// Comparing DB Versions.
let videoTitle = playlistInformation.items.videoNumber.snippet.title as NSString
print(videoTitle)
The error I get is:
Error: could not decode data into struct
I guess it has something to do with the "items" in the struct, as it is an array... but I have no idea about how to solve that.
Given that items is an array, you have to model it as an array and not a struct:
// Build a model object to import the JSON data.
struct PlaylistInformation: Decodable {
struct Item: Decodable {
struct Snippet: Decodable {
let title: String
}
let snippet: Snippet
}
let items: [Item]
}
And then access each item using its index, e.g.
let videoTitle = playlistInformation.items[0].snippet.title as NSString
print(videoTitle)
Yes, the error was coming from the "items" in the struct as it is an array.
The correct Decodable struct is:
struct PlaylistInformation: Decodable {
struct Items: Decodable {
struct Snippet: Decodable {
struct Thumbnails: Decodable {
struct High: Decodable {
let url: String
}
let high: High
}
struct ResourceId: Decodable {
let videoId: String
}
let publishedAt: String
let title: String
let thumbnails: Thumbnails
let resourceId: ResourceId
}
let snippet: Snippet
}
let items: [Items]
}
Thank you for your help.
I have list Json result based on that I created struct but while parsing getting an error typeMismatch. I am not able to find what's wrong going while create structs in code
I have created struct based on json which is not working for me
["status": "1",
"error": false,
"data": [
{
"order_id": "11",
"order_unique_id": "ORDR-1001",
"store_name": "24X7",
"otp_store": "781103",
"product": [
"Product One",
"Product Two"
],
"qty": [
"1",
"3"
],
"user_details": {
"name": "test",
"number": "98145314586",
"landmark": "test",
"area": "Bow East",
"pincode": "E3 9EG",
"place": "Home"
},
"status": "2",
"date": "2018-12-13",
"time": "14:37:57"
}]
struct RunnerStatus: Decodable {
var status: String
var error: Bool
var data: [Runner]
}
struct Runner: Decodable {
var order_id: String
var order_unique_id: String
var store_name: String
var otp_store: String
var product: [Product]
var qty: [Quantity]
var user_details: [UserDetails]
var status: String
var date: String
var time: String
}
struct Product: Decodable {
var ProductName: String
}
struct Quantity: Decodable {
var qty: String
}
struct UserDetails: Decodable {
var name: String
var number: String
var landmark: String
var area: String
var pincode: String
var place: String
}
all struct should bind with there associated value/Data
I think you structure should be as follows:
// 1
struct RootClass : Codable {
let data : [RunnerData]?
let error : Bool?
let status : String?
}
// 2
struct RunnerData : Codable {
let date : String?
let orderId : String?
let orderUniqueId : String?
let otpStore : String?
let product : [String]?
let qty : [String]?
let status : String?
let storeName : String?
let time : String?
let userDetails : UserDetail?
enum CodingKeys: String, CodingKey {
case date
case orderId = "order_id"
case orderUniqueId = "order_unique_id"
case otpStore = "otp_store"
case product
case qty
case status
case storeName = "store_name"
case time
case userDetails = "user_details"
}
}
// 3
struct UserDetail : Codable {
let area : String?
let landmark : String?
let name : String?
let number : String?
let pincode : String?
let place : String?
}
I hope this will help you. Let me know still you have any query.
If you create JSON structure manually than before you should have proper knowledge of making structure. Otherwise it's effect on JSONDecoding. There are lots of website available to make your json codable classes online, one of them is: http://www.jsoncafe.com/
Use this website to create your swift codable classes.
I am parsing a json and use this NSObject class to access values, but I cant use "description" keyword to match the key "description" in json data. The compiler says "description is a inner property in NSObject".
class JsonDetails: NSObject {
var id: NSNumber?
var title: String?
var description: String?
var address: String?
var postcode: String?
var phoneNumber: String?
var latitude: String?
var longitude: String?
var image: [Img]?
class Img: NSObject {
var small: String?
var medium: String?
var large: String?
}
}
Because "description" is already an inherited method of NSObject you cannot have a var of the same name. Renaming your var to 'desc' is an option though.