Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cellForRow(at: indexPath) returns nil and crashes my swift app

In my swift app I'm showing cells in UITableView, first 10 cells contain a photo. I've decided to add a parallax effect to each cell, so that when user scrolls the table up and down - the image changes it's offset.

This is how I fetch data from my webservice and initially add it to the tableview:

func makePostQueryForFetchingData(_ parameters: [String:AnyObject], url: String, type: String)
{
    Alamofire.request(url, method: .post, parameters: (parameters), encoding: JSONEncoding.default)
        .validate()
        .responseJSON { response in

            switch response.result {
            case .success:
                DispatchQueue.main.async(execute: {
                    items.removeAllObjects()
                    tview.reloadData()
                    if let jsonData = response.result.value as? [[String: AnyObject]] {
                        for singleJSON in jsonData {
                            if let single = SingleNode.fromJSON(JSON(singleJSON)){
                                    self.items.add(single)
                            } 
                        }
                    }  
                    self.refreshController.endRefreshing()
                    print("before crash")
                    self.tview.reloadData()
                    print("end")
                })
            case .failure(let error):
               print(error)
            } 
    }
}

When I run this function on startup - everything works well. However, if I scroll down the table and then quickly scroll up and pull to refresh - the app crashes.

In pull to refresh I'm calling the function from above.

The function for handling the parallax effect looks like this:

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (scrollView == self.tview) {
        for indexPath in self.tview.indexPathsForVisibleRows! {
            if (indexPath.row < 10) {
                print(indexPath)
                print(self.tview.cellForRow(at: indexPath))
                self.setCellImageOffset(cell: self.tview.cellForRow(at: indexPath) as! BigDetailsOnListCell, indexPath: indexPath as NSIndexPath)
            }
        }
    }
}

and I realized that when I quickly scroll the table up and refreshes it - I'm seeing in the console:

before crash
0
nil
fatal error: unexpectedly found nil while unwrapping an Optional value

so why does the self.tview.cellForRow(at: indexPath) returns nil?

like image 258
user3766930 Avatar asked Jan 16 '26 22:01

user3766930


1 Answers

cellForRow(at:) will only return a cell if the tableview currently has a visible cell for that row. It will not call your table view's data source method to obtain a cell if there is no visible cell, it will return nil.

You need to deal with the fact that cellForRow(at:) may return nil. Don't force unwrap it. Use a conditional unwrap. Similarly with indexPathsForVisibleRows; there is no good reason to force unwrap that value either.

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (scrollView == self.tview) {
        if let visiblePaths = self.tview.indexPathsForVisibleRows {
            for indexPath in visiblePaths {
                if (indexPath.row < 10) {
                   if let cell = self.tview.cellForRow(at: indexPath as? BigDetailsOnListCell) {
                    self.setCellImageOffset(cell: cell, indexPath: indexPath as NSIndexPath)
                }
            }
        }
    }
}
like image 152
Paulw11 Avatar answered Jan 19 '26 11:01

Paulw11



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!