Getting data but not able to display correctly - ios

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()
}

Related

store dictionary into userdefault as single array - Alamofire - SwiftyJSon

{
"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")

how to map the data which has array of data

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)
}

Needs to show the list of items in label with based on the format coming from response

I have an api call response where i will get the list of items as two format.
"items" : [
{
"menu_code" : "NDS",
"name" : "Monday"
},
{
"menu_code" : "NDN",
"name" : "Tuesday"
}
]
format 2 is here :
"items" : [
{
"unit" : "Nos",
"name" : "Chapathi\/Pulkas",
"quantity" : 2
},
{
"unit" : "Cup",
"name" : "Palya\/Curry",
"quantity" : 1
}
]
Now i have one label in my collection view. So based the response in my label i needs to show like below example :
name - quantity unit ,
name - quantity unit,
name - quantity unit ...etc based on the count coming from response.
Another format :
name - menu_code,
name - menu_code,
name - menu_code ..etc
based on the count coming from response.
My model class :
struct Item : Codable {
let unit : String?
let name : String?
let quantity : Int?
let menuCode : String?
}
my collection view :
var names:[String] = []
var qty:[Int] = []
var unit:[String] = []
var menuCode:[String] = []
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
cell.productName.text = self.allCategory[indexPath.item].menuName
let itemsData = self.allCategory[indexPath.row].items
print(itemsData)
for dt in itemsData {
// print(dt)
let nam = dt.name
let unt = dt.unit
let mCode = dt.menuCode
let qtys = dt.quantity
names.append(nam ?? "")
unit.append(unt ?? "" )
qty.append(qtys ?? 0)
menuCode.append(mCode ?? "" )
// cell.ProductsubLabel.text = itemsData
}
return cell
}
So i have created an array but not sure how to append to label.And also i am not aware to difference the two format and to show in the label.Any help on this.
Thanks in advance !
Update :
third new format :
"items" : [
{
"unit" : "Nos",
"product_name" : "Chapathi\/Pulkas",
"quantity" : 2
},
{
"unit" : "Cup",
"product_name" : "Palya\/Curry",
"quantity" : 1
}
]
A quite efficient solution is to add a description property in the struct which returns the appropriate data. If unit does not exist return the menuCode information otherwise quantity and unit
struct Item : Codable {
let unit : String?
let name : String?
let productName : String?
let quantity : Int?
let menuCode : String?
var description : String {
let name = self.name ?? self.productName ?? "n/a"
if unit == nil {
return "\(name) - \(menuCode!)"
} else {
return "\(name) - \(quantity!) \(unit!)"
}
}
}
In cellForItemAt map the items to their descriptions and join the array by comma.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
let category = self.allCategory[indexPath.item]
cell.productName.text = category.menuName
let itemsData = category.items
let subData = itemsData.map {$0.description}.joined(separator: ", ")
cell.ProductsubLabel.text = subData
print(subData)
return cell
}
And delete the four ugly arrays above cellForItemAt

JSON to Multidimensional Array

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")]]

How to create a function to show reviews in a view of my application (Swift-JSON)

I'm following https://developers.google.com/places/web-service/details this doc to add all the information about a place, and for example to add "geometry"
"geometry" : {
"location" : {
"lat" : -33.866651,
"lng" : 151.195827
},
i created this function in my class that work well
private let geometryKey = "geometry"
private let locationKey = "location"
private let latitudeKey = "lat"
private let longitudeKey = "lng"
class EClass: NSObject {
var location: CLLocationCoordinate2D?
init(placeInfo:[String: Any]) {
placeId = placeInfo["place_id"] as! String
// coordinates
if let g = placeInfo[geometryKey] as? [String:Any] {
if let l = g[locationKey] as? [String:Double] {
if let lat = l[latitudeKey], let lng = l[longitudeKey] {
location = CLLocationCoordinate2D.init(latitude: lat, longitude: lng)
}
}
}
}
but but i'm having difficulty adding "reviews"
"reviews" : [
{
"author_name" : "Robert Ardill",
"author_url" : "https://www.google.com/maps/contrib/106422854611155436041/reviews",
"language" : "en",
"profile_photo_url" : "https://lh3.googleusercontent.com/-T47KxWuAoJU/AAAAAAAAAAI/AAAAAAAAAZo/BDmyI12BZAs/s128-c0x00000000-cc-rp-mo-ba1/photo.jpg",
"rating" : 5,
"relative_time_description" : "a month ago",
"text" : "Awesome offices. Great facilities, location and views. Staff are great hosts",
"time" : 1491144016
}
],
i tried to follow the same concept of the function i created for geometry like this
if let t = place.details?["reviews"] as? [String:Any] {
if let n = t["author_name"], let m = t["text"] {
Mylabel.text = "\(t)"
}
but is not working, i also tried to add a breakpoint and only the first line enters. What can i do? How can i create a build to show the review with a label or anything i need?
Take advantage of Codable in Swift 4. You can simply convert your JSON into a specific struct. e.g. Based on your JSON:
let json = """
{
"reviews" : [
{
"author_name" : "Robert Ardill",
"author_url" : "https://www.google.com/maps/contrib/106422854611155436041/reviews",
"language" : "en",
"profile_photo_url" : "https://lh3.googleusercontent.com/-T47KxWuAoJU/AAAAAAAAAAI/AAAAAAAAAZo/BDmyI12BZAs/s128-c0x00000000-cc-rp-mo-ba1/photo.jpg",
"rating" : 5,
"relative_time_description" : "a month ago",
"text" : "Awesome offices. Great facilities, location and views. Staff are great hosts",
"time" : 1491144016
}
]
}
"""
You can convert it into a Response struct using the following code:
struct Response: Codable {
struct Review: Codable, CustomStringConvertible {
let text: String
let authorName: String
var description: String {
return "Review text: \(text) authorName: \(authorName)"
}
enum CodingKeys: String, CodingKey {
case text
case authorName = "author_name"
}
}
let reviews: [Review]
}
do {
if let data = json.data(using: .utf8) {
let decoder = JSONDecoder()
let decoded = try decoder.decode(Response.self, from: data)
print(decoded.reviews)
} else {
print("data is not available")
}
} catch (let e) {
print(e)
}
In your code t is not a Dictionary it is an Array instead. So try doing something like this. Rest of that you can change as per your logic.
if let t = place.details?["reviews"] as? [String:Any] {
for dic in t {
if let n = dic["author_name"], let m = dic["text"] {
Mylabel.text = "\(t)"
}
}
}
Yeah, but You can also try to make it like that:
struct reviews: Codable{
var reviews: [review]?
}
struct review: Codable{
var author_name: String?
var author_url: String?
var language: String?
var profile_photo_url: String?
var rating: Int?
var relative_time_description: String?
var text: String?
var time: Int?
}
And then:
if let dict = place.details?["reviews"] as? [String: Any],
let dataToDecode = dict.data(using: .utf8){
do{
let decodedReviews = try JSONDecoder().decode(reviews.self, from: dataToDecode)
// here you have decoded reviews in array
}catch let err{
print(err)
}
}

Resources