user372382
user372382

Reputation: 183

I keep on receiving a layout error when I add a new cell to a collection view

I am trying to add data from one view controller to a collection view controller which adds an element to the datasource array and then adds a cell to the collection view.

prepareforsegue in previous ViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "unwindToCollectionView"{
        let CVC = segue.destination as! CollectionViewController
        if let image = image{
        CVC.images.insert(imagePost(image:image), at: 0)
            print("Image is not nil")
        }
        let index = IndexPath(item: 0, section: 0)
        //CVC.collectionView?.reloadData()

        CVC.collectionView?.collectionViewLayout.invalidateLayout()
        CVC.collectionView?.layoutIfNeeded()
        CVC.collectionView?.insertItems(at: [index])
        //CVC.collectionView?.reloadItems(at: [index])
        print("In prepare for segue: \(CVC.images.count)")
    }
}

collectionViewController cellForItemAt

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
    // Configure the cell
    cell.cellImageView.image = images[indexPath.row].image

    cell.cellImageView.clipsToBounds = true
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    layout.itemSize = CGSize(width: (UIScreen.main.bounds.width-1)/2, height: (UIScreen.main.bounds.width-1)/2)
    layout.minimumInteritemSpacing = 1
    layout.minimumLineSpacing = 1
    collectionView.collectionViewLayout = layout
    cell.cellImageView.layer.cornerRadius = CGFloat((cell.cellImageView.frame.width)/2)
    return cell
}

Error received:

2018-01-25 11:43:16.228902-0500 CAR+CV(1.0)Server[4182:1181750] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot set the layout [] for [; layer = ; contentOffset: {0, -88}; contentSize: {375, 573}; adjustedContentInset: {88, 0, 83, 0}> collection view layout: ] during an update.

Upvotes: 0

Views: 782

Answers (1)

DonMag
DonMag

Reputation: 77567

Very wrong way to do this...

First, set your collectionViewLayout in viewDidLoad()

Next, in prepareForSegue, you want to modify the collection view's Data, not the collection view itself.

So...

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "unwindToCollectionView"{
        let CVC = segue.destination as! CollectionViewController
        if let image = image {
            // add the image to the CollectionViewController's data 
            CVC.images.insert(imagePost(image:image), at: 0)
            print("Image is not nil")
        }
        print("In prepare for segue: \(CVC.images.count)")
    }
}

Then, your collection view's cellForItemAt is simply:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell

    // Configure the cell
    cell.cellImageView.image = images[indexPath.row].image

    // don't do this here...
    // cell.cellImageView.clipsToBounds = true
    // cell.cellImageView.layer.cornerRadius = CGFloat((cell.cellImageView.frame.width)/2)

    return cell
}

Edit: as a side note, setting .cornerRadius should not be done in cellForItemAt either, as the cell will not be laid-out yet. Much better to subclass UIImageView and set the .cornerRadius in layoutSubviews()


Edit 2:

class RoundImageView: UIImageView {

    override func layoutSubviews() {
        super.layoutSubviews()

        self.clipsToBounds = true
        self.layer.cornerRadius = self.frame.width / 2.0

    }

}

Just set the Class of your current UIImageView to RoundImageView.

"where do I call insertItems(at:[index])"

You don't need to do that. When your segue moves to the view controller, your collection view will reload and the image you just inserted into your images array will become the first cell. I notice your segue identifier is "unwindToCollectionView" - so if your collection view does not automatically reload, add this to the VC holding the collection view:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    collectionView.reloadData()
}

Upvotes: 1

Related Questions