Search code examples
iosjsonswiftdictionaryget

How to create struct and init values from GET url in swift


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.


Solution

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