UICollectionView错误:必须通过调用 - :-dequeueReusableCellWithReuseIdentifier:forIndexPath来检索单元格:

时间:2018-03-09 07:56:06

标签: ios swift uitableview uicollectionview

在我的项目中,我有多种类型的UITableview单元格,每个单元格都包含UICollectionview

最初我在tableViewcell的2个部分中加载了2个UITableview。首先,它没有任何问题加载正常。如果我滚动第一部分它会滚动很好但是当我尝试滚动第二部分时它会给我以下错误:

  

从-collectionView:cellForItemAtIndexPath返回的单元格:没有reuseIdentifier - 必须通过调用-dequeueReusableCellWithReuseIdentifier来检索单元格:forIndexPath:

我有以下代码来设置过程:

    class Home: UITableViewDelegate, UITableViewDataSource, UICollectionViewDelegate, UICollectionViewDataSource{

     override func viewDidLoad() {
        self.tableView.register(SliderViewCell.nib, forCellReuseIdentifier: SliderViewCell.identifier)
        self.tableView.register(GridViewCell.nib, forCellReuseIdentifier: GridViewCell.identifier)
        self.tableView.estimatedRowHeight = 80
        self.tableView.rowHeight = UITableViewAutomaticDimension

}
func numberOfSections(in tableView: UITableView) -> Int {
    return 2
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

    let viewObj = self.viewObject[indexPath.section]
    if viewObj.itemType! == HomeViewItemType.Slider.rawValue{
    if let sliderCell = cell as? SliderViewCell {
        sliderCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
    }
    }
    else if viewObj.itemType! == HomeViewItemType.Grid.rawValue{
    if let gridCell = cell as? GridViewCell {
        gridCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
    }
    }


}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if self.viewObject.count>0{
    let viewObj = self.viewObject[indexPath.section]
    if viewObj.itemType! == HomeViewItemType.Slider.rawValue{
        let cell:SliderViewCell = tableView.dequeueReusableCell(withIdentifier: SliderViewCell.identifier, for: indexPath) as! SliderViewCell
        cell.contentView.tag = indexPath.section
    return cell
}
else if viewObj.itemType! == HomeViewItemType.Grid.rawValue{
        let cell:GridViewCell = tableView.dequeueReusableCell(withIdentifier: GridViewCell.identifier, for: indexPath) as! GridViewCell
        cell.contentView.tag = indexPath.section
        return cell
}
    }
    return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print("selected")
}

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

        return self.viewObject[section].viewData.count

}

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

    if viewObj.itemType! == HomeViewItemType.Slider.rawValue{
        if let cell:SliderCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: SliderCollectionViewCell.identifier, for: indexPath) as? SliderCollectionViewCell{

            if viewObj.viewData.count>0{
                if let imageURL = URL(string: viewData.imageLink!){
                    cell.icon.sd_setImage(with: imageURL, completed: nil)
                }
            }
            return cell
        }
    }
    else if viewObj.itemType! == HomeViewItemType.Grid.rawValue{
if let cell:GridCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: GridCollectionViewCell.identifier, for: indexPath) as? GridCollectionViewCell{

            if viewObj.viewData.count>0{
                if let imageURL = URL(string: viewData.icon!){
                    cell.icon.sd_setImage(with: imageURL, completed: nil)
                }

            }

            return cell
}
    }

    return UICollectionViewCell()
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    print("tapped")
}

    }

class SliderViewCell: UITableViewCell {

@IBOutlet weak var collectionView: UICollectionView!
static var nib:UINib {
    return UINib(nibName: identifier, bundle: nil)
}
static var identifier:String {
    return String(describing: SliderViewCell.self)
}
var collectionViewCellWidth : CGFloat = 15.0
var collectionViewCellHeight : CGFloat = 150.0
var cellSpaceWidth : CGFloat = 8.0

override func awakeFromNib() {
    super.awakeFromNib()
    self.configureCollectionViewCell(nibFile: SliderCollectionViewCell.nib, identifier: SliderCollectionViewCell.identifier, width: collectionView.frame.size.width, height: 80, topInset: 0, leftInset: 0, bottomInset: 0, rightInset: 0, cellSpace: cellSpaceWidth, interimSpace: 0.0, scrollInDirection: .horizontal)
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}
}
class GridViewCell: UITableViewCell {

@IBOutlet weak var collectionView: UICollectionView!
static var nib:UINib {
    return UINib(nibName: identifier, bundle: nil)
}
static var identifier:String {
    return String(describing: GridViewCell.self)
}
var collectionViewCellWidth : CGFloat = 15.0
var collectionViewCellHeight : CGFloat = 150.0
var cellSpaceWidth : CGFloat = 8.0

override func awakeFromNib() {
    super.awakeFromNib()
    self.configureCollectionViewCell(nibFile: GridCollectionViewCell.nib, identifier: GridCollectionViewCell.identifier, width: collectionView.frame.size.width, height: 80, topInset: 0, leftInset: 0, bottomInset: 0, rightInset: 0, cellSpace: cellSpaceWidth, interimSpace: 0.0, scrollInDirection: .horizontal)
}

func configureCollectionViewCell(nibFile:UINib, identifier:String,width:CGFloat,height:CGFloat, topInset:CGFloat,leftInset:CGFloat,bottomInset:CGFloat,rightInset:CGFloat, cellSpace:CGFloat, interimSpace:CGFloat,scrollInDirection:UICollectionViewScrollDirection){

    let nib = nibFile
    collectionView.register(nib, forCellWithReuseIdentifier: identifier)
    let cellWidth : CGFloat = width//collectionView.frame.size.width
    let cellheight : CGFloat = height//collectionViewCellHeight
    let cellSize = CGSize(width: cellWidth , height:cellheight)
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = scrollInDirection
    layout.itemSize = cellSize
    layout.sectionInset = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
    layout.minimumLineSpacing = cellSpace
    layout.minimumInteritemSpacing = interimSpace
    collectionView.setCollectionViewLayout(layout, animated: true)
    collectionView.reloadData()

}
override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}
    }

    extension GridViewCell{

func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forRow row:Int){

    collectionView.delegate = dataSourceDelegate
    collectionView.dataSource = dataSourceDelegate
    collectionView.reloadData()

}
}

我认为在UITableview的第二部分中加载的GridViewCell会导致问题。但我已经在dequeueReusableCellWithReuseIdentifier方法中添加了collectionView:cellForItemAtIndexPath:。所以我一无所知导致错误。

非常感谢任何帮助。

6 个答案:

答案 0 :(得分:5)

可能是因为您在

中返回UICollectionViewCell()而导致问题
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

如果不满足这两个条件。

如果在任何时候条件都不满足,则返回一个未通过调用dequeueReusableCellWithReuseIdentifier:forIndexPath:检索的单元格,如异常所示。

尝试设置断点以确认这是否是实际发生的情况。

答案 1 :(得分:2)

这也发生在我身上,代码如下:

func collectionView(_ collectionView: UICollectionView, cellForItemAt 
indexPath: IndexPath) -> UICollectionViewCell {
    
        guard let cell = 
collectionView.dequeueReusableCell(withReuseIdentifier: 
"selectedUserCell", for: indexPath) as? selectedUserCell  else { return 
UICollectionViewCell() }
    
        return cell
    
    
    }

问题是我忘记将类 selectedUserCell 分配给 storyboard/nib 中的单元格..所以一旦修复,就会返回正确的单元格。

答案 2 :(得分:1)

以下是两种可用于处理单元格的方法,而不是if else,然后是UICollectionViewCell()

let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)

        if let gridCell = cell as? GridCollectionViewCell {
            // TODO: configure cell
        }

return cell

另一种方式是

    guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
 as? GridCollectionViewCell else {

                //Handle error first so you can return a perfect cell if there is no error
  }

删除UICollectionViewCell()导致问题,因为该单元格没有重用标识符。

答案 3 :(得分:0)

选择集合视图单元格并添加重用标识符

enter image description here

答案 4 :(得分:0)

我怀疑错误来自此行return UICollectionViewCell(),您是否可以使用assert来检查错误情况?

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

    // ....

    // I doubt error come from `return UICollectionViewCell()`
    // Could you insert `assert` to check error condition ?
    // assert(false,'Error condition for collectionView cell')
    return UICollectionViewCell()
}

答案 5 :(得分:0)

我解决了这个问题 我错过了在一个集合视图中返回单元格。我正在使用多个集合视图,但我错过了返回单元格 ” let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CropName", for: indexPath) as! CropNameCollectionViewCell 返回单元格

看到你错过的地方返回单元格