I am having difficulties parsing data (JSON-like I get from endpoint) to Swift structs. As it seems data I get from the endpoint is not a valid JSON (at least not all of it looking at the structure of object = (...)), so I can't decode ListStruct.
Should I parse it another way? Any advice much appreciated
Structs I prepared are:
struct Response:Codable {
let message:String?
let list:ListStruct?
let error:Bool?
}
struct ListStruct:Codable {
let object1:[Object1]?
let object2:[Object2]?
let object3:[Object3]?
}
struct Object1:Codable {
id:Int?
name:String?
}
...
Example of data I get from endpoint:
["message": <null>, "list": {
object1 = (
{
id = 1;
name = "testing1";
}
);
object2 = (
{
files = (
);
id = 1;
name = "testing2-1";
photos = (
);
},
{
files = (
);
id = 2;
name = "testing2-2";
photos = (
);
systemId = 8;
}
);
object3 = (
{
id = 6;
name = "testing3-1";
},
{
id = 13;
name = "testing3-2";
}
);
}, "error": 0]
EDIT
How I am trying do decode:
if let result = try JSONDecoder().decode(Response?.self, from: "\(response!)".data(using: .utf8)! ) {
print("\(result)")
}
Error I am getting:
Error: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in object around character 6." UserInfo={NSDebugDescription=No string key for value in object around character 6.})))
Most probably, you are passing the wrong data object by creating using string interpolation. If the response type is Data then you don't need to recreate it again in the below line,
if let result = try JSONDecoder().decode(Response?.self, from: "\(response!)".data(using: .utf8)! ) {
Try to pass the response as it is. Shown below,
if let result = try JSONDecoder().decode(Response?.self, from: response!) {
Here is a complete testable example where the correct data object is created using the json in question and error type in Response is changed from Optional Bool to Int,
struct Response:Codable {
let message:String?
let list:ListStruct?
let error: Int?
}
struct ListStruct: Codable {
let object1:[Object1]?
let object2:[Object2]?
let object3:[Object3]?
}
struct Object1: Codable {
var id:Int?
var name:String?
}
struct Object2: Codable {
var id:Int?
var name:String?
var systemId: Int?
}
struct Object3: Codable {
var id:Int?
var name:String?
}
Usage:
let data = """
{"message": null,
"list": {
"object1": [
{
"id": 1,
"name": "testing1"
}
],
"object2" : [
{
"files" : [
],
"id" : 1,
"name" : "testing2-1",
"photos" : [
]
},
{
"files" : [
],
"id" : 2,
"name" : "testing2-2",
"photos" : [
],
"systemId" : 8
}
],
"object3" : [
{
"id" : 6,
"name" : "testing3-1",
},
{
"id" : 13,
"name" : "testing3-2",
}
]
},
"error": 0
}
""".data(using: .utf8)!
if let result = try! JSONDecoder().decode(Response?.self, from: data) {
result.list?.object1?.forEach({ obj in
print(obj.name)
})
result.list?.object2?.forEach({ obj in
print(obj.name)
})
result.list?.object3?.forEach({ obj in
print(obj.name)
})
}
Output:
Optional("testing1")
Optional("testing2-1")
Optional("testing2-2")
Optional("testing3-1")
Optional("testing3-2")
Related
Currently working with an API, and while I have successfully gotten it to decode the full result, I am only interested in the Entities/identifier portion. While I have gotten it working and get what I want/need I feel like this could be done better and more elegant and maybe in a single step. Any insight/suggestions appreciated.
JSON returned from API:
{
"count": 4596,
"entities": [
{
"facet_ids": [
"contact",
"siftery",
"investor",
"ipqwery",
"aberdeen",
"apptopia",
"semrush",
"company",
"rank",
"builtwith",
"bombora",
"key_event"
],
"identifier": {
"uuid": "468bef9f-2f50-590e-6e78-62e3adb05aa1",
"value": "Citi",
"image_id": "v1417152861/pdgwqt8ddecult5ktvdf.jpg",
"permalink": "citigroup",
"entity_def_id": "organization"
},
"short_description": "Citigroup is a diversified financial services holding company that provides various financial products and services."
},
{
"facet_ids": [
"contact",
"siftery",
"investor",
"apptopia",
"semrush",
"company",
"rank",
"builtwith",
"key_event"
],
"identifier": {
"uuid": "031a344b-c2b9-e60b-d950-1ae062026fde",
"value": "Citi",
"image_id": "yzlzhjqpparamrswaqa1",
"permalink": "citi-2",
"entity_def_id": "organization"
},
"short_description": "CITi is an NPO supporting the ICT sector in Western Cape."
},
{
"facet_ids": [
"contact",
"siftery",
"semrush",
"company",
"rank",
"builtwith",
"bombora"
],
"identifier": {
"uuid": "7ce45379-957c-49c5-bca2-c9ffd521f7da",
"value": "CITI",
"image_id": "qbkqndm7d0wgbogxjcrs",
"permalink": "citi-f7da",
"entity_def_id": "organization"
},
"short_description": "CITI trusted gateway to project-based change expertise that major organisations need to thrive, change and innovate."
}
]
}
Structs:
struct Entity: Decodable, Identifiable
{
var id: String
var companyName: String
var permalink: String
var imageID: String
init(from entity: Entities.Entity) throws
{
self.id = entity.identifier?.uuid ?? ""
self.companyName = entity.identifier?.value ?? ""
self.permalink = entity.identifier?.permalink ?? ""
self.imageID = entity.identifier?.image_id ?? ""
}
}
struct Entities: Decodable
{
var count:Int?
var entities: [Entity]?
struct Entity: Decodable
{
var facet_ids:[String]?
var identifier:Identifier?
var short_description:String?
}
struct Identifier:Decodable
{
var permalink:String?
var value:String?
var image_id:String?
var entity_def_id:String?
var uuid:String?
}
}
Call to decode:
if let data = data{
do {
let businessEntities = try decoder.decode(Entities.self, from: data)
let entities:[Entity] = try businessEntities.entities!.compactMap{
entity in
do
{
return try Entity(from: entity)
}
}
Thinking you are just interested in the Entities/identifier, you can simplify your model. Here's an example:
typealias Entities = [Entitie]
struct Entitie: Codable {
let facetIDS: [String]
let identifier: Identifier
let shortDescription: String
enum CodingKeys: String, CodingKey {
case facetIDS = "facet_ids"
case identifier
case shortDescription = "short_description"
}
}
struct Identifier: Codable {
let uuid, value, imageID, permalink: String
let entityDefID: String
enum CodingKeys: String, CodingKey {
case uuid, value
case imageID = "image_id"
case permalink
case entityDefID = "entity_def_id"
}
}
You can access entities object and decode it like this:
guard let data = data,
let jsonDict = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let entitiesObj = jsonDict["entities"] else { return }
do {
let entitiesData = try JSONSerialization.data(withJSONObject: entitiesObj)
let result = try JSONDecoder().decode(Entities.self, from: entitiesData)
} catch {
print(error.localizedDescription)
}
Obs: I created the CodingKeys because I use camelCase in my projects, you can left it in snake_case just remember to replace variables.
I'm new to the Wikipedia API and I have been trying to parse the image url from the API. The JSON I'm trying to parse is as follows:
API:
https://en.wikipedia.org/w/api.php?action=query&titles=tokyo&prop=pageimages&format=json
JSON Result:
{"batchcomplete": "",
"query": {
"normalized": [
{
"from": "tokyo",
"to": "Tokyo"
}
],
"pages": {
"30057": {
"pageid": 30057,
"ns": 0,
"title": "Tokyo",
"thumbnail": {
"source": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_of_Shinjuku_2009_January.jpg/50px-Skyscrapers_of_Shinjuku_2009_January.jpg",
"width": 50,
"height": 27
},
"pageimage": "Skyscrapers_of_Shinjuku_2009_January.jpg"
}
}
}
}
Below are the struct I created to parse the data. I can see the url when I print it to the console, but since "source" is nested under "thumbnail", which lives in the value of the [String:Page] dict pair, I can't figure out a way to access it. How do I parse data in a dictionary like this? Thank you for your help in advance.
struct WikiAPIResults: Codable {
let batchcomplete: String?
let query: Query?
}
struct Query: Codable {
let normalized: [Normalized]?
let pages: [String:Pages]? // <- I can get to here
}
struct Normalized: Codable {
let from, to: String?
}
struct Pages: Codable {
let pageid, ns: Int?
let title: String?
let thumbnail: Thumbnail?
let pageimage: String?
}
struct Thumbnail: Codable {
let source: String? // <- But I want to grab this
let width, height: Int?
}
func fetchImageFromWikipedia(imageKeyword: String, completion: #escaping (WikiAPIResults) -> Void) {
var urlComponents = URLComponents(string: "https://en.wikipedia.org/w/api.php?")!
urlComponents.queryItems = [
"action": "query",
"titles": imageKeyword,
"prop": "pageimages",
"format": "json"].map { URLQueryItem(name: $0.key, value: $0.value) }
let task = URLSession.shared.dataTask(with: urlComponents.url!) { data, response, error in
let jsonDecoder = JSONDecoder()
if let data = data,
let result = try? jsonDecoder.decode(WikiAPIResults.self, from: data) {
completion(result)
}
}
task.resume()
}
fetchImageFromWikipedia(imageKeyword: "Tokyo") { result in
print(result.query?.pages?.values)
}
Do you mean gathering all thumbnail sources?
fetchImageFromWikipedia(imageKeyword: "Tokyo") { result in
let pages = result.query?.pages?.compactMap { $0.value } ?? []
let thumbnailSources = pages.compactMap { $0.thumbnail?.source }
print(thumbnailSources)
}
This works with your example perfectly:
import Foundation
struct Response: Decodable {
struct Query: Decodable {
struct NormalizedQuery: Decodable {
let from: String
let to: String
}
struct Page: Decodable {
struct Thumbnail: Decodable {
let source: URL
let width: Int
let height: Int
}
let id: Int
let ns: Int
let title: String
let thumbnail: Thumbnail
let pageImage: String
private enum CodingKeys: String, CodingKey {
case id = "pageid"
case ns
case title
case thumbnail
case pageImage = "pageimage"
}
}
let normalized: [NormalizedQuery]
let pages: [String : Page]
}
let batchComplete: String
let query: Query
private enum CodingKeys: String, CodingKey {
case batchComplete = "batchcomplete"
case query
}
}
let responseString = """
{
"batchcomplete" : "",
"query" : {
"normalized" : [
{
"from" : "tokyo",
"to" : "Tokyo"
}
],
"pages" : {
"30057" : {
"pageid" : 30057,
"ns" : 0,
"title" : "Tokyo",
"thumbnail" : {
"source" : "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_of_Shinjuku_2009_January.jpg/50px-Skyscrapers_of_Shinjuku_2009_January.jpg",
"width" : 50,
"height" : 27
},
"pageimage" : "Skyscrapers_of_Shinjuku_2009_January.jpg"
}
}
}
}
"""
let responseData = responseString.data(using: .utf8)!
let response = try! JSONDecoder().decode(Response.self, from: responseData)
print(response)
// Response(batchComplete: "", query: __lldb_expr_18.Response.Query(normalized: [__lldb_expr_18.Response.Query.NormalizedQuery(from: "tokyo", to: "Tokyo")], pages: ["30057": __lldb_expr_18.Response.Query.Page(id: 30057, ns: 0, title: "Tokyo", thumbnail: __lldb_expr_18.Response.Query.Page.Thumbnail(source: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_of_Shinjuku_2009_January.jpg/50px-Skyscrapers_of_Shinjuku_2009_January.jpg, width: 50, height: 27), pageImage: "Skyscrapers_of_Shinjuku_2009_January.jpg")]))
I am trying to parse JSON data from a post request and I am struggling with the outcome. I would like to parse the JSON data in the Swift 5 programming language.
I have spent hours trying to figure this out. I am very confused on how to deal with multiple levels of hiarchy like this.
I dont need all the data i just need time and total_amount_sent.
Swift
struct Response: Codable {
var txs: [ResponseData]
enum CodingKeys: String, CodingKey {
case txs
}
}
struct ResponseData: Codable {
var time: String?
var total_amount_sent: String?
var recipient: String?
var txid: String?
var amount: String?
}
let url = URL(string: paramURL)!
let json: [String: Any] = [
"key": "value"
]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: json)
let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in
do {
let json = try JSONDecoder().decode(Response.self, from: data!)
print(json)
json.txs.forEach { charge in
let transaction_time = charge.time
let transaction_txid = charge.txid
let transaction_total_amount_sent = charge.total_amount_sent
print(transaction_time)
print(transaction_txid)
print(transaction_total_amount_sent)
}
} catch {
print("Error! \(error)")
}
})
task.resume()
Error:
Error! keyNotFound(CodingKeys(stringValue: "txs", intValue: nil),
Swift.DecodingError.Context(codingPath: [], debugDescription: "No
value associated with key CodingKeys(stringValue: "txs", intValue:
nil) ("txs").", underlyingError: nil))
JSON:
{
"status" : "success",
"data" : {
"network" : "DOGETEST",
"txs" : [
{
"txid" : "df4ac3ecfc356d9e10325cd4043a4103602599b71a91ea96cb3fa3204c61264c",
"from_green_address" : false,
"time" : 1620076250,
"confirmations" : 5,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "2.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "d983739751a6170d336016ffa1b7d7f2849a4a81cb0021e03a2cc6d76c55379d",
"from_green_address" : false,
"time" : 1620076071,
"confirmations" : 6,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "2.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "1dce7dd99f6a655ca82a94c8e088576c78e4ece94995f2f90891b8f5f31a54db",
"from_green_address" : false,
"time" : 1620076021,
"confirmations" : 6,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "8.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "27719e8fae3bb64f1ecec8ac64a2135d1ccc5d9219040dceaec9d24e4b17a466",
"from_green_address" : false,
"time" : 1620075780,
"confirmations" : 6,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "4.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "2a6547411b15442b78b118981cf5632e3faedec8941aea22453d8837807d37be",
"from_green_address" : false,
"time" : 1620075743,
"confirmations" : 7,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "2.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "63a145cbdc48c1e644fa52a30ed26d66c58b685698104a549001d0fe539816ba",
"from_green_address" : false,
"time" : 1620075697,
"confirmations" : 7,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "4.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "ff350583e0cb1396a3d5cc09350697daf111626ec5a3b893f8e936276f1c6715",
"from_green_address" : false,
"time" : 1620075677,
"confirmations" : 7,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "2.00000000"
}
],
"senders" : [
"2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
},
{
"txid" : "5a0115a9f608f3d01caee03587253fc58e0ad0c602f4e95e6c0db1e11703af84",
"from_green_address" : false,
"time" : 1619998414,
"confirmations" : 227,
"amounts_received" : [
{
"recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
"amount" : "1000.00000000"
}
],
"senders" : [
"2MytwDpHWpdoVYQ7JzYwBPxQ5XsEdiV7udZ"
],
"confidence" : 1.0,
"propagated_by_nodes" : null
}
]
}
}
Your model was not properly structured.
struct Response: Decodable {
var txs: [ResponseData]
enum CodingKeys: CodingKey {
case data
}
enum ValueCodingKeys: CodingKey {
case txs
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let nestedContainer = try container.nestedContainer(keyedBy: ValueCodingKeys.self, forKey: .data)
txs = try nestedContainer.decode([ResponseData].self, forKey: .txs)
}
}
struct ResponseData: Decodable {
var time: Int?
var txid: String?
var amountsReceived: [AmoutReceived]
}
struct AmoutReceived: Decodable {
var recipient: String?
var amount: String?
}
Use .convertFromSnakeCase.
Hope you are handling error cases properly. Here is the code
func fetch(urlString: String, callback: #escaping (Result<Response, Error>) -> Void) {
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else {
if let error = error {
callback(.failure(error))
}
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(Response.self, from: data)
callback(.success(result))
} catch {
callback(.failure(error))
}
}.resume()
}
You can use tools such as Quicktype.io to create a model from a JSON. This is an example model from your provided JSON. You can play around with this tool, and also there is an option "Renders output in a Swift 5 compatible mode" since you are asking about parsing in Swift 5 programming language.
import Foundation
struct User: Codable {
let status: String
let data: DataClass
}
struct DataClass: Codable {
let network: String
let txs: [Tx]
}
struct Tx: Codable {
let txid: String
let fromGreenAddress: Bool
let time, confirmations: Int
let amountsReceived: [AmountsReceived]
let senders: [String]
let confidence: Int
let propagatedByNodes: JSONNull?
enum CodingKeys: String, CodingKey {
case txid
case fromGreenAddress = "from_green_address"
case time, confirmations
case amountsReceived = "amounts_received"
case senders, confidence
case propagatedByNodes = "propagated_by_nodes"
}
}
struct AmountsReceived: Codable {
let recipient, amount: String
}
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
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()
}
}
I'm trying to parse Youtube api in using Alamofire in Swift 4
so far i did get the results and all fine but i'm having trouble accessing the "items"
so basically i want to access title, description, medium thumbnails url and resultsPerPage.
i tried a lot of solutions but non if them worked for me specially i'm using Swift4 and Alamofire
JSON:
{
"kind":"youtube#searchListResponse",
"etag":"\"XI7nbFXulYBIpL0ayR_gDh3eu1k/N6oV8CScLhAtqc_fDnA3Nw4U3RA\"",
"nextPageToken":"CBkQAA",
"regionCode":"US",
"pageInfo":{
"totalResults":922098,
"resultsPerPage":25
},
"items":[
{
"kind":"youtube#searchResult",
"etag":"\"XI7nbFXulYBIpL0ayR_gDh3eu1k/Oxu5v7t2PHcDK4wvSo-xsIp3Raw\"",
"id":{ },
"snippet":{
"publishedAt":"2011-03-21T08:32:25.000Z",
"channelId":"UC1r4VtVE__5K6c_L_3Vlxxg",
"title":"fouseyTUBE",
"description":"",
"thumbnails":{
"default":{
"url":"https://yt3.ggpht.com/-oBs78-0JLws/AAAAAAAAAAI/AAAAAAAAAAA/zKWHSghRD3U/s88-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"medium":{
"url":"https://yt3.ggpht.com/-oBs78-0JLws/AAAAAAAAAAI/AAAAAAAAAAA/zKWHSghRD3U/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"high":{
"url":"https://yt3.ggpht.com/-oBs78-0JLws/AAAAAAAAAAI/AAAAAAAAAAA/zKWHSghRD3U/s800-c-k-no-mo-rj-c0xffffff/photo.jpg"
}
},
"channelTitle":"fouseyTUBE",
"liveBroadcastContent":"none"
}
}
]
}
My Code :
let url = "https://www.googleapis.com/youtube/v3/search"
let parameters = ["q": searchText, "maxResults": 25, "part": "snippet", "type":"video", "key": "MY_YOUTUBE_API_KEY"] as [String : Any]
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseData { (dataResponse) in
if let err = dataResponse.error {
print("Failed to contact server", err)
return
}
guard let data = dataResponse.data else {return}
do{
let searchResult = try
JSONDecoder().decode(SearchResults.self, from: data)
print("Results Count:", searchResult.kind)
searchResult.items.forEach({ (data) in
print(searchResult.items["data"]["items"])
})
self.musics = searchResult.items
self.tableView.reloadData()
}catch let decodeErr {
print("Failed to Descode: ", decodeErr)
}
}
}
struct SearchResults: Decodable{
let kind: String
let items: [Music]
}
Music.Swift file
struct Music: Decodable {
var etag: String?
var kind: String?
//let time: String
}
I would suggest creating decodable struct for each nested elements like so,
struct PageInfo: Decodable {
var totalResults = 0
var resultsPerPage = 0
}
struct Snippet: Decodable {
var channelId = ""
var title = ""
var description = ""
var channelTitle = ""
var thumbnails: Thumbnail
}
struct ChannelURL: Decodable {
var url = ""
}
struct Thumbnail: Decodable {
var medium: ChannelURL
var high: ChannelURL
}
struct Item: Decodable {
var kind = ""
var etag = ""
var snippet: Snippet
}
struct Result: Decodable {
var kind = ""
var etag = ""
var pageInfo: PageInfo
var items: [Item]
}
And then proceed with the decoding. The following decoding works with your response above.
do {
let decoded = try JSONDecoder().decode(Result.self, from: data)
debugPrint(decoded)
//Now access the data
print(decoded.pageInfo.resultsPerPage) // 25
//since the items is array we take first for now
if let firstItem = decoded.items.first {
//to print the first one
print(firstItem.snippet.channelTitle) // "fouseyTUBE"
//same for URL
print(firstItem.snippet.thumbnails.medium.url) // https://yt3.ggpht.com/-oBs78-0JLws/AAAAAAAAAAI/AAAAAAAAAAA/zKWHSghRD3U/s240-c-k-no-mo-rj-c0xffffff/photo.jpg
}
} catch {
debugPrint("\(error.localizedDescription)")
}
This is the best case scenario were all data is present. So you will have to modify your structure accordingly making some values ``
My JSON is like:
{
"status": 1,
"msg": "Category Product List",
"product_data": [{
"product_id": "49",
"image": "http://192.168.1.78/Linkon/site/pub/static/frontend/Linkon/default/en_US/Magento_Catalog/images/product/placeholder/image.jpg",
"shopName": "putin",
"review": "",
"rating": "2",
"productName": "ccd",
"customrFirstName": "devi",
"customrLastName": "ss",
"address": "6th Ln, S.T.Colony, Mahalaxminagar, Rajarampuri, Kolhapur, Maharashtra 416008, India",
"contactNumber": null,
"description": "<p>ccd</p>"
},
{
"product_id": "50",
"image": "http://192.168.1.78/Linkon/site/pub/static/frontend/Linkon/default/en_US/Magento_Catalog/images/product/placeholder/image.jpg",
"shopName": "putin",
"review": "",
"rating": "2",
"productName": "car garage",
"customrFirstName": "devi",
"customrLastName": "ss",
"address": "6th Ln, S.T.Colony, Mahalaxminagar, Rajarampuri, Kolhapur, Maharashtra 416008, India",
"contactNumber": null,
"description": "<p>car garage</p>"
}
]
}
So my question is: How to create JSON model class and parse using swifty JSON?
I would recommend ditching SwiftyJSON in favor of the built-in Codable and JSONDecoder support in Swift 4.
For this, you simply define a struct that matches your JSON format, and decode it:
struct Data: Codable {
let status: Int
let msg: String
let products: [Product]
enum CodingKeys: String, CodingKey {
case status, msg
case products = "product_data"
}
}
struct Product: Codable {
let product_id, image, shopName, review: String
let rating, productName, customrFirstName, customrLastName: String
let address: String
let contactNumber: String?
let description: String
}
do {
let data = try JSONDecoder().decode(Data.self, from: json)
print("\(data.msg)") // e.g.
} catch {
print("\(error)")
}
You can create your data model class like below:
import UIKit
import SwiftyJSON
class ProductModels: NSObject {
var productModel:[ProductModel]?
}
public init(json:JSON) {
self.productModel = json["product_data"].dictionary
}
class ProductModel: NSObject {
var productID:String?
var image:String?
var shopName:String?
var review:String?
var rating:String?
var productName:String?
var customrFirstName:String?
var customrLastName:String?
var address:String?
var contactNumber:String?
var description:String?
public init(json:JSON) {
self.productID = json["product_id"].string
self. image = json["image"].string
self. shopName = json["shopName"].string
self. review = json["review"].string
self. rating = json["rating"].string
self. productName = json["productName"].string
self. customrFirstName = json["customrFirstName"].string
self. customrLastName = json["customrLastName"].string
self. address = json["address"].string
self. contactNumber = json["contactNumber"].string
self. description = json["description"].string
}
}
and can use this class by passing response from model who is calling api and getting this response example below: (the class where you are using this below code, you have to import SwiftyJSON)
Alamofire.request(//(your method or api call).responseJSON(completionHandler: { (response) in
switch response.result {
case .success(let value):
let productJson = JSON(value)
let productsData = ProductModels(json: productJson)
break;
}
})
You can create class using SwiftyJSONAccelerator
Get SwiftyJSONAccelerator from Here: https://github.com/insanoid/SwiftyJSONAccelerator
or you can create it online using https://app.quicktype.io/