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