getting crash while retrieving dict from JSON by index wise - ios

i am retrieving data by index from JSON let me show you my response
{
"contraventionsData" : [
{
"id" : "1",
"contravention_id" : "314",
"question" : "Last Gas Boiler Service date (Noted on boiler)",
"Options" : [
{
"action" : "Yes"
},
{
"action" : "Further Investigation \/ Maintenance"
},
{
"action" : "N\/A"
}
]
},
{
"id" : "2",
"contravention_id" : "314",
"question" : "Is Gas Boiler due a service? (Over 12 Months)",
"Options" : [
{
"action" : "Yes"
},
{
"action" : "Maintenance Attention"
},
{
"action" : "N\/A"
}
]
},
{
"id" : "3",
"contravention_id" : "314",
"question" : "Gas heating system \/ boiler working ok?",
"Options" : [
{
"action" : "Yes"
},
{
"action" : "Maintenance Attention"
},
{
"action" : "N\/A"
}
]
},
{
"id" : "4",
"contravention_id" : "314",
"question" : "Copy of Current Service Cert give to tenant",
"Options" : [
{
"action" : "Yes"
},
{
"action" : "Tenant to be provided with copy of current service cert"
},
{
"action" : "N\/A"
}
]
}
],
"message" : "Successfully.",
"success" : "1"
}
here is my response and i am retrieving by index like below
Code
func actionListAPI(){
let preferences = UserDefaults.standard
let uid = "u_id"
let acTkn = "acc_tkn"
let u_ID = preferences.object(forKey: uid)
let A_Token = preferences.object(forKey: acTkn)
let params = ["user_id": u_ID!, "access_token": A_Token!,"contraventions_id": conID!]
print(params)
SVProgressHUD.show()
Alamofire.request(reg6contraventionsquestions, method: .post, parameters: params).responseJSON(completionHandler: {(response) in
switch response.result{
case.success(let value):
let json = JSON(value)
print(json)
let data = json["contraventionsData"]
if data == []{
}else{
let sampleArray = data.array
let firstdict = sampleArray![0]
print(firstdict)
let question = firstdict["question"].stringValue
self.lblQue1.text = question
let sampleArray1 = data.array
let firstdict1 = sampleArray1![1]
print(firstdict1)
let question1 = firstdict1["question"].stringValue
self.lblQue2.text = question1
let sampleArray2 = data.array
let firstdict2 = sampleArray2![2]
print(firstdict2)
let question2 = firstdict2["question"].stringValue
self.lblQue3.text = question2
}
SVProgressHUD.dismiss()
case.failure(let error):
print(error.localizedDescription)
}
})
}
so issue is that when i am getting only two dict in response then i am getting crash on 3rd index so how to handel error please tell me i have maximum 4 question in response
how to handel error pelase some one tell me

Rather than hard-code the indices use a loop
var questions = [[String:Any]]()
if let sampleArray = data.array {
for dict in sampleArray {
print(dict)
questions.append(dict)
}
}
Or much simpler
if let sampleArray = data.array {
questions = sampleArray
}
or if you need the index
if let sampleArray = data.array {
for (index, dict) in sampleArray.enumerated() {
print(dict, index)
questions.append(dict)
}
}

You could use a switch inside a for loop to handle the different id values, this will not generate an error when array is shorter
for item in sampleArray {
if let id = item["id"] as? Int {
let question = item["question"] as? String ?? ""
switch id {
case 1:
self.lblQue1.text = question
case 2:
self.lblQue2.text = question
case 3:
self.lblQue3.text = question
case 4:
self.lblQue4.text = question
default:
print("error, unsupported id: \(id)")
}
}
}

Related

How to convert json into dictionary for POST api call Swift

How to convert json into dictionary for POST api call Swift
info contains an array of object that have User and Address keys You need
let dict1 : [String:Any] = ["ID" : "User123", "Name" : "Virat", "UserID" : 0]
let dict2 : [String:Any] = ["city" : "Delhi", "pin" : 123]
let addressDict : [String:Any] = ["User" : dict1,"Address" : dict2]
let infoDict : [String:Any] = ["info" :[addressDict]]
To better understand look to
// MARK: - Empty
struct Empty: Codable {
let info: [Info]
}
// MARK: - Info
struct Info: Codable {
let user: User
let address: Address
enum CodingKeys: String, CodingKey {
case user = "User"
case address = "Address"
}
}
// MARK: - Address
struct Address: Codable {
let city: String
let pin: Int
}
// MARK: - User
struct User: Codable {
let id, name: String
let userID: Int
enum CodingKeys: String, CodingKey {
case id = "ID"
case name = "Name"
case userID = "UserID"
}
}
You can also use the models above and convert the model to Data with JSONEncodable
The issue is that you're adding user and address as separate dictionaries on the array.
The JSON you posted has an array for info key but its ONE dictionary with two keys.
You need to combine the address and user dicts into one declaration and then wrap that in an array.
For ex:
let dict1 : [String:Any] = ["ID" : "User123", "Name" : "Virat", "UserID" : 0]
let dict2 : [String:Any] = ["city" : "Delhi", "pin" : 123]
let dicts : [String:Any] = ["User": dict1, "Address" : dict2]
let arr = [dicts]
let infoDict : [String:Any] = ["info" : arr]
EDIT: I would agree with SH_Khan that a much better way of doing this would be to create a Codable model
The issue is you are make dictionary per object.
try this code:
let userDict : [String:Any] = ["ID" : "User123", "Name" : "Virat", "UserID" : 0]
let addressDict : [String:Any] = ["city" : "Delhi", "pin" : 123]
let infoDict : [String:Any] = ["info" : ["User": addressDict, "Address": addressDict]]
Try this:
func getDictionaryFromString(_ json: String) -> [String: Any]? {
if let data = json.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
let json = """
{"info": [{
"User": {"ID": "user123",
"Name": "Virat",
"UserID": 0
},
"Address": {"city": "Delhi",
"pin": 123
}
}
]
}
"""
if let dict = getDictionaryFromString(json) {
print(dict["info"] as! NSArray)
}
}
//Printed:
> (
> {
> Address = {
> city = Delhi;
> pin = 123;
> };
> User = {
> ID = user123;
> Name = Virat;
> UserID = 0;
> };
> } )

Array of dictionary filter using predicate - swift3

I have array of dictionaries.
>[{"name": "John",
"address":
{"home": "addr1",
"work": "add2"}
},
{"name": "Anu",
"address": {"home": "addr1",
"work": "add2"}
}]
I am saving it to user default like this -
let personsData1 = ["name": "John", "address": {"home": "addr1", "work": "add2"}] as [String : Any]
let personsData2 = ["name": "Anu", "address": {"home": "addr1", "work": "add2"}] as [String : Any]
var persons = [personsData, personsData1]
UserDefaults.standard.set(forKey: "persons")
Retrieving it in another method and filter them on the basis of name.
let name = "John"
Getting below error
Cannot invoke 'filter' with an argument list of type '((Any?) -> Bool)'
Here is the code :-
func test () {
let personData1 = ["name": "John", "addresses": ["home":"addr1", "work": "addr2"]] as [String : Any]
let personData2 = ["name": "And", "addresses": ["home":"addr1", "work": "addr2"]] as [String : Any]
let persons = [personData1, personData2]
(UserDefaults.standard.set(persons, forKey: "persons")
print("Saved ----\(UserDefaults.standard.value(forKey: "persons"))")
if let savedPersons = UserDefaults.standard.value(forKey: "persons") {
let namePredicate = NSPredicate(format: "name like %#", name);
var filteredArray: [[String:Any]] = savedPersons.filter { namePredicate.evaluate(with: $0) }
print("names = \(filteredArray)")
}
}
If I try to filter like this -
let filteredArray = savedBrs.filter { $0["name"] == name }
getting different error -
Value of type 'Any' has no member 'filter'
With NSPredicate
let arr = [["name":"Rego","address":["one":"peek","two":"geelo"]],["name":"pppp","address":["one":"peek","two":"geelo"]]]
let neededName = "Rego"
let pre = NSPredicate(format: "name == %#",neededName)
let result = arr.filter { pre.evaluate(with:$0) }
print(result)
Without NSPredicate
let result = arr.filter { $0["name"] as? String == neededName }

How do i parse JSON, sort it in an array. Pull out the data and populate to a tableview?

i am trying to parse JSON into an array. Sort it according the highest appointment made. And then use that new array to populate it on leaderboard tableview.
I am using SwiftJson
Stuck on sorting into array
Would need to populate Name and the rest of the values in tableview in descending order.
Here are my snippets.
let jsonUrl = URL(string: url)
URLSession.shared.dataTask(with: jsonUrl!) { (data, response, error) in
guard let data = data else { return }
let jsonResult : JSON = JSON(data)
print(jsonResult)
} .resume()
Here are the output
{
"Activities" : {
"AHiHr9bzGXcN7pxvR68wulD9zqE3" : {
"Case Closed" : "2",
"Name" : "Tim Mac",
"Appointment Made" : "2",
"Prospects Met" : "2",
"Policy Servicing" : "2"
},
"gDKBlbeMsiUUFaASOLn6eOdCIrJ3" : {
"Case Closed" : "1",
"Name" : "Jane Simpson",
"Appointment Made" : "1",
"Prospects Met" : "1",
"Policy Servicing" : "1"
},
"W8uWoLf9qRX4a9BgXjLw5VZXjFu1" : {
"Case Closed" : "3",
"Name" : "John Doe",
"Appointment Made" : "4",
"Prospects Met" : "3",
"Policy Servicing" : "2"
}
}
}
you can get all values as Array of Dictionary and Sort it Like :
guard let Activities = jsonResult?["Activities"] as? [String:AnyObject] else {
return
}
var values = [Dictionary<String, AnyObject>]()
for (_, value) in Activities {
values.append(value as! Dictionary<String, AnyObject>)
}
let sorted = values.sorted { (dic1, dic2) -> Bool in
Int(dic1["Appointment Made"] as? String ?? "") ?? 0 > Int(dic2["Appointment Made"] as? String ?? "") ?? 0
}
print(sorted)
// model your data
for item in sorted {
let model = Model.init(jsonData: item)
// use model
}
// your model
class Model: NSObject {
var caseClosed :Int?
var name :String?
var appointmentMade :Int?
var prospectsMet :Int?
var policyServicing :Int?
override init() {
super.init()
}
init(jsonData : [String:AnyObject]) {
// map data to object
}
}
Use JsonSerialisation jsonObjectWithData to convert jSon response to NSArray object. And run a for loop, access every element in array as NSDictionary and compare their values for highest appointment.
To know more about accessing values from NSDictionary, apple docs reference
To know more about working with json in swift, apple docs reference.
I have tried this sorting:
let activitiesDict = jsonData?["Activities"] as? [String:Any]
let activitiesArray = activitiesDict.map({ [$0.0 : $0.1] })
let sortedActivitiesArray = self.activitiesArray.sorted {
(Int((($0 as! Dictionary<String, Any>)["Appointment Made"] as? String)!))! > (Int((($1 as! Dictionary<String, Any>)["Appointment Made"] as? String)!))!
}
print(sortedActivitiesArray)
Hope it helps.

Swift & Firebase - Could not cast value of type '__NSDictionaryM'

I am using Swift with Firebase and I am a little bit confused with this error : Could not cast value of type '__NSDictionaryM' (0x122ab6130) to 'Repeat.Expression' (0x1100004c0).
Here is a sample of the JSON file I use :
{
"levels" : {
"level1" : {
"coverImage" : "lvl1",
"expressions" : [ {
"expression" : "Yes",
"id" : 0
}, {
"expression" : "Yes",
"id" : 1
}, {
"expression" : "Yes",
"id" : 2
}, {
"expression" : "Yes",
"id" : 3
} ],
"id" : 0,
"title" : "Essentiel"
},
"level2" : {
...
},
}
}
Here are the two models I use :
struct Level {
let id : Int
let coverImage : String
let title : String
let expressions : [Expression]
}
struct Expression {
let id : Int
let expression : String
}
Finally, here is the function I use to fetch the levels :
var levels = [Level]()
func fetchLevels() {
FIRDatabase.database().reference().child("levels").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
if let levelId = dictionary["id"], let levelCoverImage = dictionary["coverImage"], let levelTitle = dictionary["title"], let levelExpressions = dictionary["expressions"] {
let level = Level(
id: levelId as! Int,
coverImage: levelCoverImage as! String,
title: levelTitle as! String,
expressions: levelExpressions as! [Expression]
)
self.levels.append(level)
}
DispatchQueue.main.async{
self.collectionView?.reloadData()
}
}
}, withCancel: nil)
}
It appears that the problem is at the line expressions: levelExpressions as! [Expression]
Thank you very much for your help.
Have a good day.
let levelExpressions = dictionary["expressions"]
The above line returns array of dictionaries i.e.[[String:Any]] and needs to require that value to be mapped into your struct Expression.This can be done in 2 ways:-
1) You can use ObjectMapper to typecast the return value of above code.
2) Manually allocate the Expression object by parsing the return values of
let levelExpressions = dictionary["expressions"] as! [[String:Any]] and assigning them to properties id and expression

How do I read a Firebase Snapshot and store a particular key-value pair in a universal array?

How do I extract the URL of every snapshot result found and append it to an array in Swift?
Snap (palettes) {
"-KSoMzY6OYPyXnOPeZMb" = {
0 = "#000000";
1 = "#423831";
2 = "#2C2923";
3 = "#424131";
4 = "#35382A";
URL = test;
};
"-KSoN-LT8I--3m-BBbfw" = {
0 = "#000000";
1 = "#F6DBC5";
2 = "#E0D6BE";
3 = "#F6F6C5";
4 = "#E1ECBD";
URL = test2;
};
Here's my returning JSON structure for example after calling:
databaseRef.child("palettes").queryOrdered(byChild: "0").queryEqual(toValue: text).observeSingleEvent(of: .value, with: { (snapshot) in
print (snapshot)
})
How do I extract the URL of the multiple result snapshot and then append it to an array in Swift so the end result becomes array = [test, test2]?
Thanks.
Edit
Here's my JSON tree:
{
"palettes" : {
"-KSoMzY6OYPyXnOPeZMb" : {
"0" : "#000000",
"1" : "#423831",
"2" : "#2C2923",
"3" : "#424131",
"4" : "#35382A",
"URL" : "test"
},
"-KSoN-LT8I--3m-BBbfw" : {
"0" : "#000000",
"1" : "#F6DBC5",
"2" : "#E0D6BE",
"3" : "#F6F6C5",
"4" : "#E1ECBD",
"URL" : "test2"
},
"-KSoN-e0huiOxyj0jadl" : {
"0" : "#F1CBC1",
"1" : "#FBE1C9",
"2" : "#E5DCC2",
"3" : "#FBFBC9",
"4" : "#000000",
"URL" : "test3"
},
"-KSqFcPjjtRkRDbzH-lc" : {
"0" : "#27643A",
"1" : "#2B6E52",
"2" : "#000000",
"3" : "#2B676E",
"4" : "#274E64",
"URL" : "test4"
}
}
}
Try this:-
var arrayVar = [String]()
FIRDatabase.database().reference().child("palletes").observeSingleEvent(of: .value, with: {(snap) in
if let snapDict = snap.value as? [String:AnyObject]{
for each in snapDict as [String:AnyObject]{
let _URL = each.value["URL"] as! String
arrayVar.append(_URL)
}
}
})

Resources