Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialTony Warner
1,631 PointsHow does didSelectItemAtIndexPath work with a CollectionView?
I've been trying to figure out how to do this with a CollectionView. I have an array of photos I get from a backend (Parse). When the user clicks on a cell, I want them to go to the detailView, where the photo they clicked on will present. What is the equivalent for didSelectItemAtIndexPath for CollectionView? I've tried "indexPathForCell," but that has a parameter of UICollectionViewCell, which gets an error. I've tried "indexPathsForItems," and that doesn't work either. There is NO resource on the whole internet that gives this answer. When loading objects from a backend, (or, let's say, how I'm trying it now, from an array filled by the backend), how do you do the didSelectItemAtIndexPath and prepareForSegue for a CollectionView? Please help me.
3 Answers
Martin Wildfeuer
Courses Plus Student 11,071 PointsThe UICollectionViewDelegate Protocol Reference of the Apple Docs states that the collection view delegate has a method called optional func collectionView(_ collectionView: UICollectionView,
didSelectItemAtIndexPath indexPath: NSIndexPath)
.
Just as with a tableview, you should be able to use this method and prepareForSegue subsequently
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// Init your segue transition here
}
Don't forget to set the class that contains the delegate methods as the collection view delegate, for example
collectionView.delegate = self
Moreover, make sure your cell does not contain elements that "capture" the tap, like buttons, for example.
Hope that helps :)
Tony Warner
1,631 PointsHi Martin,
Thanks for the reply. Much of what you said was helpful. I'm still having problems, though. When I tap the cell, the app crashes and I get the error: fatal error: unexpectedly found nil while unwrapping an Optional value.
I just can't figure out how to get the indexPath of a cell (UICollectionViewCell), get the photo from that cell, and pass it onto the next viewController (detailVC).
I've followed the code you mentioned (and pretty much all the code examples online).
One thing that you said that was especially helpful was not having elements that "capture" the tap. I had a button on top of the image (in the cell) because I wasn't finding a way for the image to get the tap. I deleted that (which I'm sure was a big step in the right direction). But still, now that nil while unwrapping error.
I would deeply appreciate any more help or advice you can give.
-Anthony
Martin Wildfeuer
Courses Plus Student 11,071 PointsThis kind of error sounds like you are force unwrapping something that is nil. Probably your dataSource, that is your dictionary, is probably not in sync with your collectionView. It's hard to tell without code, could you post your class here, please?
Tony Warner
1,631 PointsAlso, I'm not sure where to put the "collectionView.delegate = self" line. Under class? In viewDidLoad? In didSelectItemAtIndexPath? In prepareForSegue?
Also, the only protocol/inheritance/conformance for the class would be UICollectionViewController, correct? Meaning:
class MyCollectionViewController: UICollectionViewController { }
?
Martin Wildfeuer
Courses Plus Student 11,071 PointsviewDidLoad
is where I am usually assigning delegate and dataSource, too
- (void)viewDidLoad {
collectionView.delegate = self
collectionView.dataSource = self
}
You can connect these in Storyboard as well, as is the case with the standard UITableViewController, for example.
Subclassing the UICollectionViewController has nothing to do with the delegate and dataSource, though. You don't necessarily have to subclass a collection view, but you can add a simple collectionView to your standard view controller, connect the outlet and assign delegate and dataSource. Then your view controller has to conform to the delegate and dataSource protocol, like this
class MyViewController: UICollectionViewDataSource, UICollectionViewDelegate {
}
One tip for structuring your code:
class MyViewController {
// Connect collection view
// and set delegate/dataSoure
}
// MARK: CollectionView DataSource
extension MyViewController: UICollectionViewDataSource {
// dataSource methods go here
}
// MARK: CollectionView Delegate
extension MyViewController: UICollectionViewDelegate {
// delegate methods go here
}
this makes your code easier to read.