my JSON:
{
"id": "70",
"bname": "Municipal Corporation - Water",
"bcategoryname": "Water",
"bcustomerparms": "[{\"paramName\":\"Consumer Number\",\"dataType\":\"NUMERIC\",\"optional\":\"false\",\"minLength\":\"1\",\"maxLength\":\"10\" . },
{\"paramName\":\"Mobile Number\",\"dataType\":\"NUMERIC\",\"optional\":\"false\",\"minLength\":\"10\",\"maxLength\":\"10\"},
{\"paramName\":\"Email . Id\",\"dataType\":\"ALPHANUMERIC\",\"optional\":\"false\",\"minLength\":\"5\",\"maxLength\":\"100\"}]",
}
{
"id": "68",
"bname": "Municipal Corporation - 12",
"bcategoryname": "Water",
"bcustomerparms": "[{\"paramName\":\"K No\",\"dataType\":\"ALPHANUMERIC\",\"optional\":\"false\",\"minLength\":\"7\",\"maxLength\":\"20\"}]",
}
I am unable to create struct from get api, i need bname and its paramNamew according to its bcategoryname, i need to disply bname in table and if i select i need its all paramNames.
Here is code:
struct JsonDataBiller{
var bname: String?
var bcategoryname: String?
var bcustomerparms: [cDetails]
init(bname: String, bcategoryname: String, bcustomerparms: [cDetails]){
self.bname = bname
self.bcategoryname = bcategoryname
self.bcustomerparms = bcustomerparms
}
}
struct cDetails{
var paramName: String?
var minLength: String?
var maxLength: String?
init(paramName: String, minLength: String, maxLength: String)
{
self.paramName = paramName
self.minLength = minLength
self.maxLength = maxLength
}
}
Code:
class AllMakePaymentViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var jsonData = [JsonDataBiller]()
var minLength: String?
var maxLength: String?
var bName: String?
var category: Category?
var categoryName: String?
var paramName: String?
var ParamArray = [String]()
var labelText: String?
override func viewDidLoad() {
super.viewDidLoad()
allPaymentService()
}
func allPaymentService(){
let urlStr = "https://dev.anyemi.com/webservices/anyemi/api.php?rquest=billermdm"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
guard error == nil else {
print("error")
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
//print("the all make payment json is \(jsonObj)")
let billerdetailsArray = jsonObj["billerdetails"] as! [[String: Any]]
for billerdetail in billerdetailsArray {
self.categoryName = billerdetail["bcategoryname"] as? String
let customrParams = billerdetail["bcustomerparms"] as! String
let res = try JSONSerialization.jsonObject(with:Data(customrParams.utf8)) as! [[String: Any]]
for item in res {
self.paramName = item["paramName"] as? String
self.minLength = item["minLength"] as? String
self.maxLength = item["maxLength"] as? String
if self.categoryName == "Water"{
let bName = billerdetail["bname"] as? String
self.jsonData.append(JsonDataBiller(bname: bName ?? "", bcategoryname: self.categoryName ?? "", bcustomerparms: [paramName: paramName, minLength: minLength, maxLength: maxLength]))
}
if self.categoryName == "Electricity"{
let bName = billerdetail["bname"] as? String
self.jsonData.append(JsonDataBiller(bname: bName ?? "", bcategoryname: self.categoryName ?? "", bcustomerparms: [paramName: paramName, minLength: minLength, maxLength: maxLength]))
}
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch {
print("catch error")
} }).resume()
}
}
error:
Contextual type '[cDetails]' cannot be used with dictionary literal
Here i need to add bnam
according to its bcategoryname
and paramName
according to bname
please help me in the above code please, i am unable to solve this issue, i got stuck from long time.
You are getting close...
The key step issue is that you are looping through the "customer params" and adding a new customer object for each param, instead of adding one customer object that includes an array of params.
Take a look at this - it should run without any edits. After parsing the data, it will print the list of Water customers, along with their associated params.
The debug output should look like this:
Water count: 18
Electricity count: 71
Name: Bhopal Municipal Corporation - Water
Cat: Water
Param: Connection ID / minLength: 8 / maxLength: 8
Name: Bangalore Water Supply and Sewerage Board
Cat: Water
Param: RR Number / minLength: 8 / maxLength: 8
Name: Delhi Jal Board
Cat: Water
Param: K No / minLength: 10 / maxLength: 10
...
Name: Municipal Corporation Jalandhar
Cat: Water
Param: Account No / minLength: 1 / maxLength: 1
Param: Consumer Mobile No / minLength: 10 / maxLength: 10
Param: Consumer Email ID / minLength: 5 / maxLength: 5
Param: UID / minLength: 1 / maxLength: 1
Name: Municipal Corporation Ludhiana - Water
Cat: Water
Param: Consumer Number / minLength: 1 / maxLength: 1
Param: Mobile Number / minLength: 10 / maxLength: 10
Param: Email Id / minLength: 5 / maxLength: 5
Name: New Delhi Municipal Council (NDMC) - Water
Cat: Water
Param: Consumer Number / minLength: 7 / maxLength: 7
...
Here is the source:
//
import UIKit
struct JsonDataBiller{
var bname: String?
var bcategoryname: String?
var bcustomerparms: [cDetails]
init(bname: String, bcategoryname: String, bcustomerparms: [cDetails]){
self.bname = bname
self.bcategoryname = bcategoryname
self.bcustomerparms = bcustomerparms
}
}
struct cDetails{
var paramName: String?
var minLength: String?
var maxLength: String?
init(paramName: String, minLength: String, maxLength: String)
{
self.paramName = paramName
self.minLength = minLength
self.maxLength = maxLength
}
}
class AllMakePaymentViewController: UIViewController {
// arrays of JsonDataBiller objects for each category
var jsonWaterData = [JsonDataBiller]()
var jsonElectricityData = [JsonDataBiller]()
// ...
override func viewDidLoad() {
super.viewDidLoad()
allPaymentService()
}
func allPaymentService(){
let urlStr = "https://dev.anyemi.com/webservices/anyemi/api.php?rquest=billermdm"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
guard error == nil else {
print("error")
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
//print("the all make payment json is \(jsonObj)")
let billerdetailsArray = jsonObj["billerdetails"] as! [[String: Any]]
for billerdetail in billerdetailsArray {
// make these local vars --- no need for the confusing self. properties
let localBName = billerdetail["bname"] as? String ?? ""
let localCName = billerdetail["bcategoryname"] as? String ?? ""
let customrParams = billerdetail["bcustomerparms"] as! String
let res = try JSONSerialization.jsonObject(with:Data(customrParams.utf8)) as! [[String: Any]]
// create new array of cDetails objects
var aParams = [cDetails]()
// for each param item
for item in res {
if let pn = item["paramName"] as? String,
let minL = item["minLength"] as? String,
let maxL = item["maxLength"] as? String {
// create new cDetails object
let cd = cDetails(paramName: pn, minLength: minL, maxLength: maxL)
// append it to the aParams array
aParams.append(cd)
}
}
// create new JsonDataBiller object with
// bname
// bcategoryname
// array of bcustomerparms
let jdBiller = JsonDataBiller(bname: localBName,
bcategoryname: localCName,
bcustomerparms: aParams)
// append the JsonDataBiller object to the appropriate category array
if localCName == "Water" {
self.jsonWaterData.append(jdBiller)
}
if localCName == "Electricity" {
self.jsonElectricityData.append(jdBiller)
}
// if localCName == ...
}
// finished parsing the data into arrays of jdBiller objects
print("Water count: \(self.jsonWaterData.count)")
print("Electricity count: \(self.jsonElectricityData.count)")
print()
// for quick debugging...
self.jsonWaterData.forEach {
obj in
print("Name: \(obj.bname ?? "")")
print("Cat: \(obj.bcategoryname ?? "")")
obj.bcustomerparms.forEach {
param in
print("Param: \(param.paramName ?? "") / minLength: \(param.minLength ?? "") / maxLength: \(param.minLength ?? "")")
}
print()
}
// DispatchQueue.main.async {
// self.tableView.reloadData()
// }
}catch {
print("catch error")
} }).resume()
}
}
If you look into the property bcustomerparms
it's is a dictionary.
In the below line
let customrParams = billerdetail["bcustomerparms"] as! String
you are trying to force downcast a Dictionary
to String
so it's bound to crash.
The correct code should be
let customrParams = billerdetail["bcustomerparms"] as: [String: Any]
Here I am using force downcast too but you should really be using if let
or guard let
.
Also as the other comment's suggest you should be using Codable
protocol as it has become the go to way to deserialize json data or rather decoding it. You can find a lot of tutorials on it.
If you are struggling with creating the struct, you may try to use this website which will do it automatically:
*Still, I would advice to first understand the concept and then use such helpers
In your case, there is an issue with your JSON file.
First part of your JSON should probably look like this:
{ "id": 70, "bname": "Municipal Corporation - Water", "bcategoryname": "Water", "bcustomerparms": [ { "paramName": "Consumer Number", "dataType": "numeric", "optional": false, "minLength": 1, "maxLength": 10} ] }
// MARK: - DataStructure
struct DataStructure: Codable {
let id: Int
let bname, bcategoryname: String
let bcustomerparms: [Bcustomerparm]
}
// MARK: - Bcustomerparm
struct Bcustomerparm: Codable {
let paramName, dataType: String
let bcustomerparmOptional: Bool
let minLength, maxLength: Int
enum CodingKeys: String, CodingKey {
case paramName, dataType
case bcustomerparmOptional = "optional"
case minLength, maxLength
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.