Search code examples
iosswiftpagination

Could not cast value of type 'Swift._ContiguousArrayStorage<AppName.JobsNearBy>' (0x113b1a200) to 'AppName.JobsNearBy' (0x10e6e7e60)


I'm trying to fetch data from web and trying paging using AZTableView library. I'm facing the above error. Here's my code

My Modal class

class JobsNearBy: NSObject {
var jobId: Int?
var title: String?
var companyName: String? }

Fetch data code I fetch 10 rows from the web first time put them in object and append on array and return.

func jobsNearByFetch(pageNumber: Int, success:@escaping (_ status:Bool, _ jobsNearByArray:Any) -> (), failure:@escaping (_ message: Error) -> ()) {
let headers: HTTPHeaders = ["Accept": "application/json",
                            "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhb"]
let url = "http://thedemo.net/demo/stdinaus/api/jobs-near-me?page=\(pageNumber)&latitude=27.6947033&longitude=85.3310636"
Alamofire.request(url, headers: headers).responseJSON { response in
    guard let jobsResponse = response.result.value as? [String:Any] else{
        print("Error: \(String(describing: response.result.error))")
        failure((response.result.error! as Error))
        return
    }
    //            print("response: \(jobsResponse)")
    let jobsNearByObj:JobsNearBy = JobsNearBy()
    var jobsNearByArray:Array = [JobsNearBy]()

    let dict = jobsResponse as NSDictionary
    let status = dict["status"] as? Int
    let meta = dict["meta"] as! NSDictionary
    let lastPage = meta["last_page"] as? Int

    let dataArray = dict["data"] as! NSArray
    for dataDict in dataArray{
        let dataCompanyName = dataDict as! NSDictionary
        let jobId = dataDict as! NSDictionary
        let title = dataDict as! NSDictionary
        if let companyName = dataCompanyName["company_name"],
            let jobId = jobId["jobId"],
            let title = title["title"]{
            jobsNearByObj.companyName = companyName as? String
            jobsNearByObj.jobId = jobId as? Int
            jobsNearByObj.title = title as? String
            jobsNearByArray.append(jobsNearByObj)
        }
    }
    success(true, jobsNearByArray)
}

}

Code in AZTableViewController

override func fetchData() {
    super.fetchData()
    if Util.isConnectedToInternet(){
        self.showLoading(view: self.view, text: "Loading..")
        APIHandler.sharedInstance.jobsNearByFetch(pageNumber: 1, success: { (status, jobsArray) in
            self.stopLoading(fromView: self.view)
            self.arrayOfJobs.removeAll()
            self.arrayOfJobs.append(jobsArray as! JobsNearBy)
            self.didfetchData(resultCount: self.arrayOfJobs.count, haveMoreData: true)
        }) { (failure) in
            self.stopLoading(fromView: self.view)
            print("Failure")
        }
    }else{
        Util.showAlert(title:"Oops", message:"No internet connection..", view:self)
    }

}

override func fetchNextData() {
    super.fetchNextData()
    if Util.isConnectedToInternet(){
        self.showLoading(view: self.view, text: "Loading..")
        APIHandler.sharedInstance.jobsNearByFetch(pageNumber: 2, success: { (status, jobsArray) in
            self.stopLoading(fromView: self.view)
            self.arrayOfJobs.append(jobsArray as! JobsNearBy)
            if self.arrayOfJobs.count < 10{
                self.didfetchData(resultCount: self.arrayOfJobs.count, haveMoreData: true)
            }else{
                self.didfetchData(resultCount: self.arrayOfJobs.count, haveMoreData: false)
            }
        }) { (failure) in
            self.stopLoading(fromView: self.view)
            print("Failure")
        }
    }else{
        Util.showAlert(title:"Oops", message:"No internet connection..", view:self)
    }
}

I think I've made mistake on append line but unable to solve this. Please someone help me with the above error.


Solution

  • Your completion handler for jobsNearByFetch returns an array of JobsNearBy, which you put into jobsArray

    Then, you have a force cast of jobsArray to JobsNearBy, but it is an array, not a single instance of the object so the downcast fails and because it is a forced downcast your app crashes.

    You could fix it by using as! [JobsNearBy], but it is better to change the signature of the completion closure to indicate that it returns [JobsNearBy] instead of Any; then you don't need to downcast anything:

    You shouldn't use Any when you can determine what the actual type is. Also, you shouldn't use NSDictionary when working in Swift if you can avoid it. Also, avoid force downcasting and unwrapping whenever possible.

    Stylistically the boolean success parameter and a separate failure closure is a bit odd too; you would typically have a single closure that returns an optional Error - If error is nil then the operation was successful. I would have:

    func jobsNearByFetch(pageNumber: Int, completion:@escaping ( _ jobsNearByArray:[JobsNearBy]?, error:Error?) -> ()) {

    This way you can use a single trailing closure.

    You also need to look at your jobsNearByFetch as there are some return paths that don't call a closure.

    Finally, you should look at the Codeble protocol as it can eliminate the JSON parsing code altogether.