简体   繁体   中英

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.

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:

https://app.quicktype.io/

*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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM