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 trial

iOS Enhance a Weather App with Table Views Implementing the Detail View Passing Data to the Detail View

How 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
PLUS
Martin Wildfeuer
Courses Plus Student 11,071 Points

The 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 :)

Hi 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
Martin Wildfeuer
Courses Plus Student 11,071 Points

This 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?

Also, 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
Martin Wildfeuer
Courses Plus Student 11,071 Points

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