arraysjsonparsingswift3gloss

Cast from 'Array<JSON>' (aka 'Array<Dictionary<String, Any>>') to unrelated type 'JSON' (aka 'Dictionary<String, Any>') always fails


I'm trying to load a table with data from JSON. I want to deserialize the JSON into an array. I use a 3rd party library called Gloss, anyway, it should be easy, but I can't solve the warning (same as the title of this thread).

This is the JSON data: http://prntscr.com/d8zdb5 (it's a valid JSON, I already checked it using JSONLint)

This is my code snippet: Initialization

import Gloss
...
class CourierViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
struct courierList: Decodable{
    let shipper: String?
    let service: String?
    let cost: Int?
    let etd: String?

    init?(json: JSON){
        self.shipper = "shipper" <~~ json
        self.service = "service" <~~ json
        self.cost = "cost" <~~ json
        self.etd = "etd" <~~ json
    }
}
var TableData:Array<JSON> = Array<JSON>()
...
}

Download JSON from server:

...
override func viewDidLoad() {
    super.viewDidLoad()
    get_data_from_url(url: "https://www.imperio.co.id/project/ecommerceApp/CourierDataReq.php")
}
...
func get_data_from_url(url:String){
    self.TableData.removeAll(keepingCapacity: false)
    let parameterURL = ["dest":User_city.text!,"weight":String(CartManager.sharedInstance.totalWeightInCart())]
    Alamofire.request(url, parameters: parameterURL).validate(contentType: ["application/json"]).responseJSON{ response in
        switch response.result{
        case .success(let data):
            self.TableData.append(data as! JSON)
            DispatchQueue.main.async(execute: {
                self.tableView.reloadData()
            })
            break
        case .failure(let error):
            print("Error: \(error)")
            break
        }
    }
}

Use the array to load the tableView

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let value = TableData as? JSON, //the  warning appears in here
        let eventsArrayJSON = value["ShipperResult"] as? [JSON]
        else { fatalError() }
    let CourierList = [courierList].from(jsonArray: eventsArrayJSON)
    print((CourierList?.count)!)
    return (CourierList?.count)!
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CourierCell", for: indexPath) as! CourierTableViewCell

    if indexPath.row % 2 == 0 {
        cell.backgroundColor = UIColor(red: 200.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1.0)
    } else {
        cell.backgroundColor = UIColor(red: 135.0/255.0, green: 212.0/255.0, blue: 236.0/255.0, alpha: 1.0)
    }

    guard let value = TableData as? JSON, //The warning appears in here
        let eventsArrayJSON = value["ShipperResult"] as? [JSON]
        else { fatalError() }
    let CourierList = [courierList].from(jsonArray: eventsArrayJSON)
    for j in 0 ..< Int((CourierList?.count)!){
        cell.label_shippingCourier.text = (CourierList?[j].shipper!)!
        cell.label_shippingCourier.sizeToFit()
        cell.label_serviceName.text = (CourierList?[j].service!)!
        cell.label_serviceName.sizeToFit()
        cell.label_estCost.text = String(describing: (CourierList?[j].cost!)!)
        cell.label_estCost.sizeToFit()
        if (CourierList?[j].etd! == "") {
            cell.label_etd.text = "Data is not available"
        } else {
            cell.label_etd.text = (CourierList?[j].etd!)!
        }
        cell.label_etd.sizeToFit()
    }
    cell.selectionStyle = .none

    return cell
}

Any idea how to solve the problem? Thank you.

edit: I forget to mention that I use Swift 3.


Solution

  • @vadian Thank you so much for helping me, it's tricky mistake.

    For anyone who somehow cross this problem too, the answer is: "Don't cast array to dictionary by any chance." If you need to create an empty dictionary, read this post Swift: declare an empty dictionary