How can I parse JSON to a class when JSON has multiples arrays?
I'm trying to convert data from REST API to my classes in Swift 2.0, but I can't figure out how to do it properly, anyone can help?
/* JSON from REST API
{
"Name": "New name",
"Email": "test#test.com",
"FacebookId": "new facebook Id",
"Address": "New Address",
"Photo": "https://graph.facebook.com/novo facebook Id/picture?width=500&height=500",
"CreditCards": [
{
"Id": 5,
"LastNumber": "3123",
"Brand": "visa"
},
{
"Id": 6,
"LastNumber": "3124",
"Brand": "visa"
}
]
}
Class representation in swift?
class Client {
var fullName: String?
var email: String?
var facebookId: String?
var photo: String?
var creditCards: [CreditCard]?
required init(json: JSON) {
self.fullName = json["FullName"].string
self.email = json["Email"].string
self.facebookId = json["FacebookId"].string
self.photo = json["Photo"].string
self.creditCards = json["CreditCards"]["Id"]
}
required init() {}
}
class CreditCard {
var Id: Int?
var lastNumber: String?
var brand: String?
}
You should take a look at the NSJSONSerialization class and its methods. They do exactly what you need: converting JSON data into arrays, dictionaries, strings and numbers.
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 am trying to replicate the json format for a POST request, but I am having trouble working with the following 2D dictionary in Swift.
payload = {"cardholder": {
"address": {
"city": "city",
"state": "MA",
"street": "street",
"zip_code": "11111"
},
"shipping_address": {
"city": "city",
"state": "MA",
"street": "street",
"zip_code": "11111"
}
}}
Is there a way I can set up addressDetails and shippingDetails?
var addressDetails = ["city": self.newCity!, "state": self.newState!,"street": self.newStreet!,"zip_code": self.newZipcode!]
var shippingDetails = ["city": self.newCity!, "state": self.newState!,"street": self.newStreet!,"zip_code": self.newZipcode!]
if self.newUnit != ""{
addressDetails["unit"] = self.newUnit!
shippingDetails["unit"] = self.newUnit!
}
var test: [String:[String:[String:String]]] = ["cardholder": ["address": addressDetails]]
To answer your question: yes. Everything you need to do is add shippingDetails to the test["cardholder"] dict:
var test: [String:[String:[String:String]]] = ["cardholder": ["address": addressDetails, "shipping_address": shippingDetails]]
However, I totally agree with #Paulw11, you should not fiddle around with dictionaries that way. Use structs that conform to Codable instead:
struct Address: Codable {
var city: String
var state: String
var street: String
var zipCode: String
var unit: String?
enum CodingKeys: String, CodingKey {
case city, state, street, zipCode = "zip_code", unit
}
}
struct Cardholder: Codable {
var address: Address
var shippingAddress: Address
enum CodingKeys: String, CodingKey {
case address, shippingAddress = "shipping_address"
}
}
struct Payload: Codable {
var cardholder: Cardholder
}
...
let addressDetails = Address(city: self.newCity!, state: self.newState!, street: self.newStreet!, zipCode: self.newZipcode!, unit: self.newUnit == "" ? nil : self.newUnit)
let shippingDetails = Address(city: self.newCity!, state: self.newState!, street: self.newStreet!, zipCode: self.newZipcode!, unit: self.newUnit == "" ? nil : self.newUnit)
var test = Payload(cardholder: Cardholder(address: addressDetails, shippingAddress: shippingDetails))
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.
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/
How can I get my list data from a json object like this:
users: {
uid: {
name: "user1",
items: {
itemID1: {
name: "item1"
},
itemID2: {
name: "item2"
}
}
}
}
How can I get this list of Items and use it with an MVVM structure.
I tried to do the same thing that this article is doing with friends. But I am using firebase to load data.
https://medium.com/#stasost/ios-how-to-build-a-table-view-with-multiple-cell-types-2df91a206429
Thank you for your help!
It depends what you want if you want to display different cells for different users you ned String enum with cell registration and then have switch for them. I guess you don't want answer how to parse JSON.
For the article you need to fill the data model which looks like this
class Profile {
var fullName: String?
var pictureUrl: String?
var email: String?
var about: String?
var friends = [Friend]()
var profileAttributes = [Attribute]()
}
class Friend {
var name: String?
var pictureUrl: String?
}
class Attribute {
var key: String?
var value: String?
}
so you need data like this
users: {
uid: {
fullName: "user1",
pictureUrl: "svff",
email: "dfdf#gmail.com",
about: "Hello, world!",
friends: {
0: {
name: "Jon",
pictureUrl : "dfbdvsd"
},
1: {
name: "Tyrion",
pictureUrl : "dfbdvsd"
}
},
attributes: {
0: {
key: "key1",
value : "value1"
},
1: {
key: "key2",
value : "value2"
}
}
}
}