I'm trying to take my JSON from a HTTP POST and put it in a multidimensional array to use for sections / table cells in Swift.
I would like each table section to use these dynamic keys (submitid) and insert the cell data for each:
15302992338145
15301374235890
15302930963080
My JSON:
let swiftyJsonVar = JSON(data!)
{
"data" : {
"15302992338145" : [
{
"date" : "2018-06-27",
"username" : "user1",
"submitid" : 15302992338145,
"notes" : "Testing"
},
{
"date" : "2018-06-28",
"username" : "user1",
"submitid" : 15302992338145,
"notes" : "Testing"
}
],
"15301374235890" : [
{
"date" : "2018-06-21",
"username" : "user2",
"submitid" : 15301374235890,
"notes" : "Comments one two three"
},
{
"date" : "2018-06-22",
"username" : "user2",
"submitid" : 15301374235890,
"notes" : "N/A"
}
],
"15302930963080" : [
{
"date" : "2018-07-03",
"username" : "user3",
"submitid" : 15302930963080,
"notes" : "Hello"
}
]
}
}
I've tried but with no luck:
if let resData = swiftyJsonVar["data"][].arrayObject {
self.arrRes = resData as! [String: [[String:AnyObject]]]
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return arrRes.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath)
// Configure the cell...
var dict = arrRes[indexPath.section][indexPath.row]
cell.dateLabel?.text = dict["date"]
return cell
}
You should stop using SwiftyJSON and move up to Swift 4 and Decodable:
struct User : Decodable {
let date : String
let username : String
let submitid : Int
let notes : String
}
struct Result : Decodable {
let data : [[User]]
struct AnyCodingKey : CodingKey {
var stringValue: String
var intValue: Int?
init(_ codingKey: CodingKey) {
self.stringValue = codingKey.stringValue
self.intValue = codingKey.intValue
}
init(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
init(intValue: Int) {
self.stringValue = String(intValue)
self.intValue = intValue
}
}
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: AnyCodingKey.self)
let intermediate = try! con.decode([String:[User]].self,
forKey: AnyCodingKey(stringValue:"data"))
var data = [[User]]()
for d in intermediate {
data.append(d.value)
}
self.data = data
}
}
// jsondata is your original JSON data, as you downloaded it
let result = try! JSONDecoder().decode(Result.self, from: jsondata)
After that, result.data is an array of array of User.
[[User(date: "2018-07-03", username: "user3",
submitid: 15302930963080, notes: "Hello")],
[User(date: "2018-06-27", username: "user1",
submitid: 15302992338145, notes: "Testing"),
User(date: "2018-06-28", username: "user1",
submitid: 15302992338145, notes: "Testing")],
[User(date: "2018-06-21", username: "user2",
submitid: 15301374235890, notes: "Comments one two three"),
User(date: "2018-06-22", username: "user2",
submitid: 15301374235890, notes: "N/A")]]
Related
How to parse tree format Hierarchies Level in
ResponseData from API call currently It hold two Level Hierarchies
{
"result" : [
{
"name": "HIERARCHIES LEVELS",
"hierarchies" : [
{
"hierarchy_order" : 1,
"hierarchy_level" : 1,
"name": "LEVEL ONE",
"hierarchies" : [
{
"hierarchy_order" : 1,
"hierarchy_level" : 2,
"name": "LEVEL TWO",
"hierarchies" : [
],
"is_enabled" : true
}
],
"is_enabled" : true
},
{
"hierarchy_order" : 1,
"hierarchy_level" : 1,
"name": "LEVEL ONE",
"hierarchies" : [
{
"hierarchy_order" : 1,
"name" : "LEVEL TWO",
"hierarchy_level" : 2,
"hierarchies" : [
],
"is_enabled" : true
},
{
"hierarchy_order" : 1,
"name" : "LEVEL TWO",
"hierarchy_level" : 2,
"hierarchies" : [
],
"is_enabled" : true
}
],
"is_enabled" : true
}
]
}
]
}
ModelClass
struct AssignedHierarchyLevelModel {
let result: [Result]?
init(_ json: JSON) {
result = json["result"].arrayValue.map { Result($0) }
}
struct Result {
let name: String?
let hierarchies: [Hierarchies]?
init(_ json: JSON) {
name = json["name"].stringValue
hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) }
}
}
struct Hierarchies {
let hierarchyOrder: Int?
let hierarchyLevel: Int?
let name: String?
let hierarchies: [Hierarchies]?
let isEnabled: Bool?
init(_ json: JSON) {
hierarchyOrder = json["hierarchy_order"].intValue
hierarchyLevel = json["hierarchy_level"].intValue
name = json["name"].stringValue
hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) }
isEnabled = json["is_enabled"].boolValue
}
}
struct Hierarchies {
let hierarchyOrder: Int?
let hierarchyLevel: Int?
let name: String?
let hierarchies: [Hierarchies]?
let isEnabled: Bool?
init(_ json: JSON) {
hierarchyOrder = json["hierarchy_order"].intValue
hierarchyLevel = json["hierarchy_level"].intValue
name = json["name"].stringValue
hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) }
isEnabled = json["is_enabled"].boolValue
}
}
}
After Response
var assignedhierarchyResult = [AssignedHierarchyLevelModel.Result]()
func dataBindAccountSettingHierarchyLevel(){
hierarchyParentList.removeAll()
self.assignedhierarchyResult = self.assignedHierarchyLevelModel?.result ?? []
}
// TableView Datasource Delegate Methods
func numberOfChild(assignedhierarchyChilds: [AssignedHierarchyLevelModel.Result]) -> Int {
var arrayCount = [AssignedHierarchyLevelModel.Result.Hierarchies]()
assignedhierarchyChilds.enumerated().forEach { (indexValue,element) in
arrayCount.append(contentsOf: assignedhierarchyChilds[indexValue].hierarchies ?? [])
if arrayCount[indexValue].hierarchies?.count ?? 0 > 0 {
arrayCount[indexValue].hierarchies?.enumerated().forEach({ (subIndex, subElement) in
arrayCount.append(contentsOf: arrayCount[indexValue].hierarchies?[subIndex].hierarchies ?? [])
})
}
}
return arrayCount.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.numberOfChild(assignedhierarchyChilds: assignedhierarchyResult)
}
func numberOfSections(in tableView: UITableView) -> Int {
return assignedhierarchyResult.count
}
Trying to Hierarchy Level for tableview like AccordionLevels unable to wrappe my data set from response date. In normal tableview i display its shown Root-Parent and Child in tableview list. Unable to get sublist of child.
How to get extract data from subChild of [Hierarchies] till the end of subElement of [Hierarchies]?
to easily create Models(class/structs) for your json use Link :- https://app.quicktype.io/
And use json decoder to decode
let decoder = JSONDecoder()
let loadedData = try? decoder.decode(struc.self, from: jsonData)
-> Your Model
struct Welcome: Codable {
var result: [Result]?
}
// MARK: - Result
struct Result: Codable {
var name: String?
var hierarchies: [Hierarchy]?
}
// MARK: - Hierarchy
struct Hierarchy: Codable {
var hierarchyOrder, hierarchyLevel: Int?
var name: String?
var hierarchies: [Hierarchy]?
var isEnabled: Bool?
enum CodingKeys: String, CodingKey {
case hierarchyOrder = "hierarchy_order"
case hierarchyLevel = "hierarchy_level"
case name, hierarchies
case isEnabled = "is_enabled"
}
}
-> now you can easily use it like
let myStrut = Welcome()
myStruct.result[Index].hierarchies[Index].name
{
"message" : "success ",
"status" : "1",
"Result" : {
"name" : "abc",
"lastname" : null,
"middlename" : null,
"id" : 20431
}
}
i want to store result object into single userdefaults using model and how to retrieve it
From the docs here. Have you tried like this:
//convert the JSON to a raw String
if let rawString = json.rawString() {
userDefaults.set(rawString, forKey: "jsonData")
} else {
print("json.rawString is nil")
}
First create a model for this, using Codable protocol
struct MyJSON : Codable {
let message : String?
let status : String?
let result : JSONResult? // Don't use Result, a keyword in swift
}
struct JSONResult : Codable {
let name : String?
let lastname : String?
let middlename : String?
let id : Int?
}
Then Use the protocol to map the JSON, save the model in UserDefaults.
let jsonString =
"""
{
"message" : "success ",
"status" : "1",
"result" : {
"name" : "abc",
"lastname" : null,
"middlename" : null,
"id" : 20431
}
}
"""
let jsonData = Data(jsonString.utf8)
let data = try JSONDecoder().decode(MyJSON.self, from: jsonData)
// save model in userDefaults
func saveModel() {
if let encoded = try? JSONEncoder().encode(data) {
UserDefaults.standard.set(encoded, forKey: "MySavedValue")
}
}
//get the model
func getModel() -> MyJSON? {
guard let data = UserDefaults.standard.object(forKey: "MySavedValue") as? Data else {
return nil
}
return try? JSONDecoder().decode(MyJSON.self, from: data)
}
how to use
saveModel()
print(getModel()?.message) // print("Success")
I am fetching some data and displaying in my screen.
func getAllCatogory(){
ViewUtils.addActivityView(view: self.view)
TransportManager.sharedInstance.AllCatogory { (dt, err) in
ViewUtils.removeActivityView(view: self.view)
if let _ = err{
}else{
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let str = dt as? String else { return }
let res = try decoder.decode([AllCatagories].self, from:str.data(using: .utf8)!)
self.allCategory = res
self.collectionView.reloadData()
print(res.count) // getting count 2
print(self.allCategory.count as Any) getting count 2
}
catch {
print(error)
}
}
}
}
But in my collection view when i am going to append or print its not coming.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
let ct = self.allCategory[indexPath.item]
print(ct.menuName as Any) // getting null
//cell.productName.text = ct.menuName
return cell
}
Not sure what might be an issue.Any help on this ??
Thanks in advance !
Update :
class AllCatagories: Codable{
let image : String?
let isActive : Int?
let items : [Item]?
let menuCode : String?
let menuName : String?
enum CodingKeys: String, CodingKey {
case image
case isActive = "is_active"
case items
case menuCode = "menu_code"
case menuName = "menu_name"
}
}
struct Item : Codable {
let menuCode : String?
let name : String?
enum CodingKeys: String, CodingKey {
case menuCode = "menu_code"
case name
}
}
here is my model class which i am using for.Main thread to reload the collection view means where exactly ?
Update :
[
{
"menu_code" : "NDS",
"items" : [
{
"unit" : "Nos",
"name" : "Chapathi\/Pulkas",
"quantity" : 2
},
{
"unit" : "Cup",
"name" : "Palya\/Curry",
"quantity" : 1
}
],
"is_active" : 1,
"image" : "nds.jpg",
"menu_name" : "Normal Diet South"
},
{
"menu_code" : "NCCD",
"items" : [
{
"menu_code" : "NDS",
"name" : "Monday"
},
{
"menu_code" : "NDN",
"name" : "Tuesday"
}
],
"is_active" : 1,
"image" : "NCCD.jpg",
"menu_name" : "Normal Combo Corporate Diet"
}
]
my json response is here
If you specify convertFromSnakeCase you have to delete the coding keys, that's the purpose of convertFromSnakeCase
And declare the members / properties as much as possible non-optional, not the contrary. In this particular case you would get a Decoding error.
struct AllCatagories: Codable {
let image : String
let isActive : Int
let items : [Item]
let menuCode : String
let menuName : String
}
struct Item : Codable {
let unit : String?
let name : String
let quantity : Int?
let menuCode : String?
}
And reload the collection view on the main thread
DispatchQueue.main.async {
self.collectionView.reloadData()
}
My response is :
[
{
"menu_code" : "NDS",
"items" : [
{
"unit" : "Nos",
"name" : "Chapathi\/Pulkas",
"quantity" : 2
},
{
"unit" : "Cup",
"name" : "Palya\/Curry",
"quantity" : 1
}
],
"is_active" : 1,
"image" : "nds.jpg",
"menu_name" : "Normal Diet South"
},
{
"menu_code" : "NCCD",
"items" : [
{
"menu_code" : "NDS",
"name" : "Monday"
},
{
"menu_code" : "NDN",
"name" : "Tuesday"
}
],
"is_active" : 1,
"image" : "NCCD.jpg",
"menu_name" : "Normal Combo Corporate Diet"
}
]
Today 2 format i have .In this both format only my data will come from response.And i need to show them in collection view.
My api call :
func getAllCatogory(){
TransportManager.sharedInstance.AllCatogory { (dt, err) in
if let _ = err{
}else{
if let data = dt as? String {
let pro = Mapper<AllCatagories>().map(JSONString: data)
print(data) // getting data
print(pro as Any) // getting nil
}
}
}
}
My model :
class AllCatagories: Mappable{
var menu_code = ""
var items: Array<AllCatProducts> = []
var is_active = 0
var image = ""
var menu_name = ""
required init?(map: Map) {
}
init() {
}
func mapping(map: Map) {
menu_name <- map["menu_name"]
is_active <- map["is_active"]
menu_code <- map["menu_code"]
image <- map["image"]
items <- map["items"]
}
}
Below i have created one more model class for the item inside my json.
class AllCatProducts: Mappable{
var name = ""
var quantity = 0
var unit = ""
var menu_code = ""
required init?(map: Map) {
}
init() {
}
func mapping(map: Map) {
name <- map["name"]
quantity <- map["quantity"]
unit <- map["unit"]
menu_code <- map["menu_code"]
}
}
The issues is i am getting nil in my pro.Not sure when i am doing wrong.
Thanks
You can try
struct AllCatagories: Codable {
let menuCode: String
let items: [AllCatProducts]
let isActive: Int
let image, menuName: String
}
struct AllCatProducts: Codable {
let unit: String?
let name: String
let quantity: Int?
let menuCode: String?
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let str = dt as? String else { return }
let res = try decoder.decode([AllCatagories].self, from:str.data(using: .utf8)!)
print(res)
}
catch {
print(error)
}
I'm dealing with this. This is mi JSON response
{
"code": 200,
"message": "ok",
"data": {
"section1": [
{
"clave": "xxxx",
"orden": 0,
"nombre": "xxxxx",
"video": "xxxxx",
"imagen": "xxxxx",
"series": 0,
"repeticiones": 0,
"descanso":0,
"completado": false
},
{
"clave": "xxxx",
"orden": 0,
"nombre": "xxxxx",
"video": "xxxxx",
"imagen": "xxxxx",
"series": 0,
"repeticiones": 0,
"descanso":0,
"completado": false
}
}
],
"section2": [
{
"clave": "xxx",
"equipo": "xx",
"imagen": "x",
"tiempo": 0,
"intensidad": 0,
"completado": false
}
],
"section3": [
{
"clave": "xxx",
"nombre": "xxxx",
"imagen": "",
"completado": false
},
{
"clave": "xxx",
"nombre": "xxxx",
"imagen": "",
"completado": false
}
],
"section4": [
{
"clave": "xx",
"nombre": "xxxx",
"imagen": "x",
"completado": false
},
{
"clave": "xx",
"nombre": "xxxx",
"imagen": "x",
"completado": false
}
]
}
}
What I want to do is display the info in sections, the sections should be "section1", "section2", "section3", "section4" ,obviously and display all the info that "section1" contains, and if the section is "section2" display all the info in cardios an so on... But I want to display it in the same tableView just divided in sections Could you help me?. thanks in Advance
Since NSDictionary is not an ordered data container, you would have to use a different data structure or you would have to update the API and return an ordered array inside the "data".
First of all in the JSON above Section2 is a extraneous closing brace.
This is a starting point.
Decode the value for data as [String:[Item]] and map each dictionary to a helper struct Section containing the name (dictionary key) and the array of Item (dictionary value). The sections array is sorted by name
struct Root : Decodable {
let code : Int
let message : String
let sections : [Section]
enum CodingKeys: String, CodingKey { case code, message, sections = "data"}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
code = try container.decode(Int.self, forKey: .code)
message = try container.decode(String.self, forKey: .message)
let data = try container.decode([String : [Item]].self, forKey: .sections)
sections = data.map({Section(name: $0.0, items: $0.1)}).sorted(by: {$0.name < $1.name})
}
}
struct Section {
let name : String
let items : [Item]
}
struct Item : Decodable {
let clave : String
let completado : Bool
let repeticiones : Int?
// ... other properties
}
Decode the Root struct (data is the JSON data)
let result = try JSONDecoder().decode(Root.self, from: data)
let sections = result.sections
In the table view sections are the sections and items are the rows
Another solution should create a custom parser which will convert your data into an array of a model which would represent any section.
Model
class SomethingObj {
var clave: String?
var orden: Int?
var nombre: String?
var video: String?
var imagen: String?
var series: Int?
var repeticiones: Int?
var descanso: Int?
var completado: Bool?
init() {
}
}
Parser
private func parseData(for structure: NSDictionary) -> [[SomethingObj]] {
var sectionsArray = [[SomethingObj]]()
guard let sectionsLoop = structure["data"] as? NSDictionary else { return sectionsArray }
var sectionIndex = 1
while let sectionObjsData = sectionsLoop["section\(sectionIndex)"] as? [NSDictionary] {
var sectionArray = [SomethingObj]()
for sectionObjData in sectionObjsData {
let obj = SomethingObj()
obj.clave = sectionObjData["clave"] as? String
obj.orden = sectionObjData["orden"] as? Int
obj.nombre = sectionObjData["nombre"] as? String
obj.video = sectionObjData["video"] as? String
obj.imagen = sectionObjData["imagen"] as? String
obj.series = sectionObjData["series"] as? Int
obj.repeticiones = sectionObjData["repeticiones"] as? Int
obj.descanso = sectionObjData["descanso"] as? Int
obj.completado = sectionObjData["completado"] as? Bool
sectionArray.append(obj)
}
sectionsArray.append(sectionArray)
sectionIndex = sectionIndex + 1
}
return sectionsArray
}
Display parsed data
Use whatever you want in order to display something with your array of parsed data.