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
Swift Language Multicast Delegate
Xcode 9: Swift Dependency Analysis Error
Animating Strings Fading In/Out in Swift
Uitraitcollection Clarification
Square Video Using Avfoundation
How to Properly Handle a Nil Uiapplication.Sharedapplication().Keywindow
Ios11 Uibarbuttonitem Not Working
Swift: Triggering Tableviewcell to Lead to a Link in a Uiwebview in Another Viewcontroller
Animating Button Allowuserinteraction Not Working
Swift:How to Find the Position(X,Y) of a Letter in a Uilabel
Calculate New Coordinates with Starting Position and Distance
Custom Mkoverlayrenderer Drawmaprect Function Not Drawing Polygons
Uibezierpath + Cashapelayer - Animate a Circle Filling Up
iOS Sharecontext Tapping on Suggestion Intent Property of Extensioncontext Is Nil