LaVOZs

The World’s Largest Online Community for Developers

'; ios - Issues with casting celltypes to dequeue - LavOzs.Com

Hi i'm having issues in my cellForItemAt its saying the error below. I don't see why i'm unable to cast the cells. It occurs at the first line of the else statement.

The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.

Could not cast value of type 'Spoexs.MenuCell2' (0x10d059660) to 'Spoexs.MenuCell1' (0x10d0595c0).

import UIKit
import MIBadgeButton_Swift

class SecondMenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = UIColor.rgb(r:240, g:240, b:240)
        cv.dataSource = self
        cv.delegate = self
        return cv
    }()

    let cellId = "cellId"
    let cellId2 = "cellId2"

    let menuItems = ["inventory", "checkout", "scanner"]
    var inventoryController: InventoryTabController?

    override init(frame: CGRect){ //on run
        super.init(frame: frame)

        collectionView.register(MenuCell1.self,
                                forCellWithReuseIdentifier: cellId) //registering superclass

        collectionView.register(MenuCell2.self,
                                forCellWithReuseIdentifier: cellId) //registering superclass

        addSubview(collectionView)
        addConstraintsWithFormat("H:|[v0]|", views: collectionView)
        addConstraintsWithFormat("V:|[v0]|", views: collectionView)

        let selectedIndexPath = NSIndexPath(item:0, section:0)
        collectionView.selectItem(at: selectedIndexPath as IndexPath, animated: false, scrollPosition: []) //home button glows on run


        //setup horizontal bar
        slider()
        NotificationCenter.default.addObserver(forName: .arrayValueChanged, object: nil, queue: OperationQueue.main) { [weak self] (notif) in
            badge = "\(checkout.count)"
            self?.collectionView.reloadData()
        }
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    var horizontalBarLeftAnchorConstraint: NSLayoutConstraint?

    func slider() {
        let horizontalBarView = UIView()
        if #available(iOS 10.0, *) {
            horizontalBarView.backgroundColor = UIColor(displayP3Red:0.29, green:0.78, blue:0.47, alpha:0.2)
        } else {
            horizontalBarView.backgroundColor = UIColor.rgb(r:190, g:190, b:190)
        }
        horizontalBarView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(horizontalBarView) //add to hierarchy

        // need x,y coordinate
        horizontalBarLeftAnchorConstraint = horizontalBarView.leftAnchor.constraint(equalTo: self.leftAnchor)
        horizontalBarLeftAnchorConstraint?.isActive = true

        horizontalBarView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
        horizontalBarView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/3).isActive = true
        horizontalBarView.heightAnchor.constraint(equalToConstant: 3).isActive = true
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        inventoryController?.scrollToMenuIndex(menuIndex: indexPath.item)
        print("Right here \(indexPath.section)")
        print("Right here \(indexPath.item)")
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: frame.width/3, height: frame.height)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView,
                        numberOfItemsInSection section: Int) -> Int {
        return 3
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {


        if indexPath.section == 1{
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId2, for: indexPath) as! MenuCell2
            cell.imageView2.setImage(UIImage(named:menuItems[indexPath.section])?.withRenderingMode(.alwaysTemplate), for: .normal)
            cell.imageView2.badgeString = badge
            cell.tintColor = UIColor.rgb(r:255, g:0, b:255) //set tint color
            return cell
        } else{
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell1
            cell.imageView1.image = UIImage(named: menuItems[indexPath.section])?.withRenderingMode(.alwaysTemplate)
            cell.tintColor = UIColor.rgb(r:255, g:0, b:255) //set tint color
            return cell
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

class MenuCell1: UICollectionViewCell {

    override init(frame: CGRect){
        super.init(frame: frame)
        setupViews()

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    let imageView1: UIImageView = {
        let iv = UIImageView()
        iv.image = UIImage(named: "")?.withRenderingMode(.alwaysTemplate)
        iv.tintColor = UIColor.rgb(r:144, g:157, b:255)//set tint color of each menu image bg
        return iv
    }()


    override var isSelected: Bool {
        didSet {
            imageView1.tintColor = isSelected ? UIColor.rgb(r:76, g:200, b:120) : UIColor.rgb(r:190, g:190, b:190)  //green when selected otherwise grey
        }
    }

    func setupViews() {

        addSubview(imageView1)

        addConstraintsWithFormat("H:[v0(28)]", views: imageView1)
        addConstraintsWithFormat("V:[v0(28)]", views: imageView1)

        addConstraint(NSLayoutConstraint(item: imageView1, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier:1, constant: 0)) //center menu icons
        addConstraint(NSLayoutConstraint(item: imageView1, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier:1, constant: 0))
    }

}


class MenuCell2: UICollectionViewCell {

    override init(frame: CGRect){
        super.init(frame: frame)
        setupViews()

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    let imageView2: MIBadgeButton = {
        let button = MIBadgeButton()
        var image = UIImage(named: "home")?.withRenderingMode(.alwaysTemplate)
        button.setImage(image, for: .normal)
        button.badgeString = badge
        button.isUserInteractionEnabled = false
        button.tintColor = UIColor.rgb(r:190, g:190, b:190) //intital button tint grey
        return button
    }()

    override var isSelected: Bool {
        didSet {
            imageView2.tintColor = isSelected ? UIColor.rgb(r:76, g:200, b:120) : UIColor.rgb(r:190, g:190, b:190)  //green when selected otherwise grey
        }
    }

    func setupViews() {

        addSubview(imageView2)

        addConstraintsWithFormat("H:[v0(28)]", views: imageView2)
        addConstraintsWithFormat("V:[v0(28)]", views: imageView2)

        addConstraint(NSLayoutConstraint(item: imageView2, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier:1, constant: 0)) //center menu icons
        addConstraint(NSLayoutConstraint(item: imageView2, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier:1, constant: 0))

    }

}

Your code for registering the cell classes is wrong:

collectionView.register(MenuCell1.self, forCellWithReuseIdentifier: cellId)
collectionView.register(MenuCell2.self, forCellWithReuseIdentifier: cellId) // <-- probably not intended

You are registering both classes for the same cellId, one should be cellId2:

collectionView.register(MenuCell1.self, forCellWithReuseIdentifier: cellId)
collectionView.register(MenuCell2.self, forCellWithReuseIdentifier: cellId2)

The problem is this line:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell1

The cell you have registered for this reuse identifier is MenuCell2, so that is what you get. You cannot then magically turn it into a MenuCell1!

Related
Swift - Cast Int into enum:Int
Issue dequeuing UICollectionViewCell
“Unable to dequeue a cell with identifier” Error
Adding a custom UIViewcontroller to subview programmatically but getting an error message “Cannot convert value of type…”
Strange bug on dequeuing collectionviewcell
Dequeuing reusable cell in Swift 3 is incredibly slow
How can I programmatically make a UICollectionView fill a UITableViewCell?
The view hierarchy is not prepared for the constraint inside init with frame initializer