UICollectionView Tutorial: Reusable Views, Selection and Reordering | raywenderlich.com

In this tutorial, you’ll level up your UICollectionView skills, learning how to implement reusable views for section headers, select cells, update your layout based on selection, and reorder with drag and drop.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/9477-uicollectionview-tutorial-reusable-views-selection-and-reordering
The following line always returns nil. Any suggestions?

guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: reuseIdentifier,
for: indexPath) as? FlickrPhotoCell else {
  preconditionFailure("Invalid cell type")
  }

It’s returning a cell, otherwise there would be an exception. So the conditional cast is failing, which looks like the cell’s class isn’t set correctly in the storyboard. Check the class and the reuse identifier.

Sorry it was the wrong portion of the code. But I did check both the class identifier and the reuse identifier

EDIT: Even loaded the final project from the tutorial and it does not ever download the large image either.

func performLargeImageFetch(for indexPath: IndexPath, flickrPhoto: FlickrPhoto) {

    guard let cell = self.collectionView.cellForItem(at: indexPath) as? FlickrPhotoCell else {
      return
    }
    
    print("Getting large image")
    
    cell.activityIndicator.startAnimating()
    flickrPhoto.loadLargeImage { [weak self] (result) in
      guard let self = self else {
        return
      }
      
      switch result {
      case .results(let photo):
        if indexPath == self.largePhotoIndexPath {
          cell.imageView.image = photo.largeImage
        }
      case .error(_):
        return
      }
    }
  }

@ski081 Can you please help with this when you get a chance? Thank you - much appreciated! :]

@bratajesak, nice catch here! The cell was being requested by performLargeImageFetch before it had been returned by the cellForItem(at:) method.

Here’s how I fixed it:

Update the performLargeImageFetch method to accept the cell as a parameter:

  func performLargeImageFetch(for indexPath: IndexPath, flickrPhoto: FlickrPhoto, cell: FlickrPhotoCell) {
cell.activityIndicator.startAnimating()

flickrPhoto.loadLargeImage { [weak self] result in
  cell.activityIndicator.stopAnimating()

  guard let self = self else {
    return
  }
  
  switch result {
  case .results(let photo):
    if indexPath == self.largePhotoIndexPath {
      cell.imageView.image = photo.largeImage
    }
  case .error(_):
    return
  }
}

}

Then update the collectionView(_:cellForItemAt:) to pass the cell right before it returns it at the end of the method body:

performLargeImageFetch(for: indexPath, flickrPhoto: flickrPhoto, cell: cell)

I hope this helps. Please let me know if you have any other questions!

It doesn’t work. If I download Final Project - It is work, but if I download the starter or continue project from the previous tutorial - it doesn’t work. This tutorial is broken by a man who rewrites it. Project doesn’t download large image.

@gleb3r What errors do you get exactly?

not errors. When I tap on some image, it becomes bigger, but quality remains low. The picture is no downlod in to my app. There are no any errors.

@ski081 Do you have any feedback about this? Thank you - much appreciated! :]

@gleb3r

The cell was being requested by performLargeImageFetch before it had been returned by the cellForItem(at:) method.

Here’s how I fixed it:

Update the performLargeImageFetch method to accept the cell as a parameter:

  func performLargeImageFetch(for indexPath: IndexPath, flickrPhoto: FlickrPhoto, cell: FlickrPhotoCell) {
cell.activityIndicator.startAnimating()

flickrPhoto.loadLargeImage { [weak self] result in
  cell.activityIndicator.stopAnimating()

  guard let self = self else {
    return
  }
  
  switch result {
  case .results(let photo):
    if indexPath == self.largePhotoIndexPath {
      cell.imageView.image = photo.largeImage
    }
  case .error(_):
    return
  }
}

}

Then update the collectionView(_:cellForItemAt:) to pass the cell right before it returns it at the end of the method body:

performLargeImageFetch(for: indexPath, flickrPhoto: flickrPhoto, cell: cell)

I hope this helps. Please let me know if you have any other questions!

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!