Why Will Diddeselectitemat of Uicollectionview Throw an Error of Unexpected Found Nil and Crash the App Swift

Why will didDeselectItemAt of UICollectionView throw an error of unexpected found nil and crash the app Swift?

So the crash is happening because when selecting an item, didDeselectItemAt can be called for an item that's not visible anymore.
The UICollectionView reuses UICollectionViewCells, this means that the collectionView.cellForItem(at: indexPath) method will return nil for cells that are not visible.
To fix this you can use the following code:

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as! ImageCollectionViewCell else {
return //the cell is not visible
}

UIView.animate(withDuration: 0.3, animations: {
cell.imageView.alpha = 0.6
})
}

Some other suggestions I have for improving your code:

You have a lot of places where you're force unwrapping values.

Consider taking the following approach:

guard let url = self.collection?.imageUrls?[indexPath.row] else {
fatalError("url was nil")
}

self.selectedImageUrl = url

Alamofire.request(url).responseImage(completionHandler: {
(response) in
if response.result.value != nil {
self.selectedImage.image = response.result.value
}
})

By using the guard statement you force the app to crash with an appropriate error message, which will help you when debugging. It's a better practice compared to force unwrapping.

Also, when dequeing cells, you could go for something like this:

let cellIdentifier = "ImageCell"
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? ImageCollectionViewCell else {
fatalError("Wrong cell type")
}

This can happen when the cell type is different

Why does data returned from coredata become nil after tableview scroll in swift?

I found out eventually that it was actually a threading(concurrence) problem.

Basically, in the getSuperTrainerData function, a bunch of objects were supposed to be created. Given that they returned nill all the time, the ViewController would of course refuse to create the rows.. however, entering the same view twice would have given the app time to store and cache the objects returned from a network call.

I make a call to Utility.backgroundThread which is just a wrapper for dispatchQueue. This means that networkService was placed inside a background thread. But inside networkService there is a call to urlSession. Call to servers create their own background threads, so even though I called my server call throuhg a background thread, it created its own background thread and never returned to the main call.

The solution that I used was to just make a server call, and place the background-object-creation call in the completion handler like so:

    self.networkService.getSuperTrainerData(student: student) { (complet, returnDics, errorMessage) -> Void in
if(complet) {
DispatchQueue.global(qos: DispatchQoS.userInitiated.qosClass ).async {
self.removeSuperTrainerData();
self.createSuperTrainerData(dics: returnDics!);

DispatchQueue.main.async( execute: {
print("main queue without completion")
self.networkService.coreDataHandler.saveContext();
self.topics = Topic.getTopics(student: self.student!, context:self.networkService.coreDataHandler.context!)!;
SwiftSpinner.hide();
self.tableView.reloadData();
})
}

} else {
Utility.showAlertView(title: "LOGIN_FAILED_TITLE".localized, message: errorMessage);
}
}

Hope this helps someone :)

How can I fix crash when tap to select row after scrolling the tableview?

Because you are using reusable cells when you try to select a cell that is not in the screen anymore the app will crash as the cell is no long exist in memory, try this:

if let lastCell = self.diceFaceTable.cellForRowAtIndexPath(lastIndexPath) as! TableViewCell{
lastCell.checkImg.image = UIImage(named: "uncheck")
}
//update the data set from the table view with the change in the icon
//for the old and the new cell

This code will update the check box if the cell is currently in the screen. If it is not currently on the screen when you get the cell to reused (dequeuereusablecellwithidentifier) you should set it properly before display. To do so you will need to update the data set of the table view to contain the change.



Related Topics



Leave a reply



Submit