为啥两个表格视图单元格中的两个集合视图在 Swift 4 中不起作用?

Posted

技术标签:

【中文标题】为啥两个表格视图单元格中的两个集合视图在 Swift 4 中不起作用?【英文标题】:Why two collection views in two table view cells won't work in Swift 4?为什么两个表格视图单元格中的两个集合视图在 Swift 4 中不起作用? 【发布时间】:2017-11-28 11:52:41 【问题描述】:

我阅读了类似的问题,例如如何在多个表格视图单元格中拥有多个集合视图,我连接了我的集合视图单元格并为它们使用标识符名称,但我不知道为什么会收到此错误:

* 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法将同类视图出列:带有标识符 extera_infoCollectionViewCell 的 UICollectionElementKindCell - 必须为标识符注册一个 nib 或一个类,或者在故事板' * 首先抛出调用栈:

**请记住,我阅读了类似的问题和第一个表格视图单元格,其中集合视图运行良好,问题出在第二个 ** 这是我的主视图控制器代码,它有一个表格视图,表格视图有两个单元格

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

    if collectionView == fieldOfActivityCell().fieldofActivitiesCollectionView 
        let fullfields : String = self.adv.resultValue[0].work_field!
        let fullfieldsArr : [String] = fullfields.components(separatedBy: ",")
        print(fullfieldsArr)
        return fullfieldsArr.count

     else 

        let extera_infofields : String = self.adv.resultValue[0].extera_info!
        let extera_infofieldsArr : [String] = extera_infofields.components(separatedBy: ",")
        print(extera_infofieldsArr)
        return extera_infofieldsArr.count
    


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

    if collectionView == fieldOfActivityCell().fieldofActivitiesCollectionView 

        let fieldsCells = collectionView.dequeueReusableCell(withReuseIdentifier: "fieldOfActivityCollectionViewCell", for: indexPath) as! fieldOfActivityCollectionViewCell

        let fullfields : String = self.adv.resultValue[0].work_field!
        let fullfieldsArr : [String] = fullfields.components(separatedBy: ",")

        fieldsCells.title.text = fullfieldsArr[indexPath.row]

        return fieldsCells
    
    else 
        let extera_infoCells = collectionView.dequeueReusableCell(withReuseIdentifier: "extera_infoCollectionViewCell", for: indexPath) as! extera_infoCollectionViewCell

        let extera_info : String = self.adv.resultValue[0].extera_info!
        let extera_infoArr : [String] = extera_info.components(separatedBy: ",")

        extera_infoCells.infoText.text = extera_infoArr[indexPath.row]

        return extera_infoCells
    

这是同一视图控制器中的表格视图代码:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    if indexPath.row == 0

        let fieldCell = self.showAdvTableView.dequeueReusableCell(withIdentifier: "fieldOfActivityCell", for: indexPath) as! fieldOfActivityCell

        return fieldCell

     else 

        let fieldCell = self.showAdvTableView.dequeueReusableCell(withIdentifier: "extera_infoCell", for: indexPath) as! extera_infoCell

        return fieldCell
   

这是表格视图的第一个单元格类:

class fieldOfActivityCell: UITableViewCell 

    @IBOutlet weak var fieldofActivitiesCollectionView: UICollectionView!

    override func awakeFromNib() 
        super.awakeFromNib()
        // Initialization code

        if let flowLayout = fieldofActivitiesCollectionView.collectionViewLayout as? UICollectionViewFlowLayout  flowLayout.estimatedItemSize = CGSize.init(width: 1.0, height: 1.0) 
    

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

        // Configure the view for the selected state
    


extension fieldOfActivityCell 

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

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

这是第二个 tableview 单元类:

@IBOutlet weak var extra_infoCollectionView: UICollectionView!

override func awakeFromNib() 
    super.awakeFromNib()

    if let flowLayout = extra_infoCollectionView.collectionViewLayout as? UICollectionViewFlowLayout  flowLayout.estimatedItemSize = CGSize.init(width: 1.0, height: 1.0) 



 extension extera_infoCell 

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

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

【问题讨论】:

【参考方案1】:

第一步: 使用标签 - 你只需要为它们使用标签并使用 if else 来选择使用标签选择的集合视图,所以答案是这样的:

if collectionView.tag == 1 
do some thing//////
else 
do some thing else

你应该在 cellForRowAtIndexPath 和 numberOfRows 方法中使用它,你也可以将它用于表格视图

第二步:您必须在 CollectionView 数据源的 cellForRowAt 方法中更改要出列的“集合视图”的名称:

if collectionView.tag == 1 
    let cell = yourFirstCollectionView.dequeueReusableCell(...) as yourCell
    ....
    return cell
 else 
    let cell = yourSecondCollectionView.dequeueReusableCell(...) as yourCell
    ....
    return cell

【讨论】:

【参考方案2】:

根据您的错误,您的重用标识符与情节提要中的任何单元格都不匹配。在界面生成器中单击您的 extera_info collectionView 单元格。选择属性检查器选项卡。在 reuse identifier 下确保您放入 extera_infoCollectionViewCell

【讨论】:

正如您在我的代码中看到的那样,集合视图单元格代码将选择应该使用哪个单元格,在故事板中,我在重用标识符中写下了单元格的名称 错误信息表示sting不在情节提要中;这是情节提要中的问题,而不是代码中的问题。 您可以在照片中看到我在故事板中完成的操作【参考方案3】:

如果你把其他tableview单元格放在不同的类中,故事板的NSObject特性可以帮助你,并且易于维护。

【讨论】:

它还需要一个故事板,【参考方案4】:

上面 Saeed 的标签选项可能是最简单的答案,但发现他的描述有点短,所以在下面为以前从未使用过标签的人添加更完整的答案...

如果遵守 MVC 并将 collectionView 的 dataSource 方法放置在 UITableView 类中(而不是在 UITableViewCell 类中),并希望避免此“错误:

您使用的每个 Collection View 都需要自己的 dequeueReusableCell 标识符:

    在 interface-builder 中,为您的集合视图单元格命名所有标识符。例如 CatPicCell 和 DogPicCell。 在您的 CellForItemAt collectionView 方法中,设置 if 语句或 switch 语句,以便将每个重用标识符设置为等于您在 interface-builder 中创建的标识符(步骤 1)。如果使用 switch/case,你的值可以设置为 collectionView.tag。可以对标签进行编号以标识每个不同的 collectionView。标签就像将你的 collectionView 集合变成一个字典或数组,这样每个 collectionView 都有自己唯一的键/索引。 返回界面构建器,进入情节提要并选择每个集合视图(每个集合视图都应位于其自己的 tableView 单元格中)。在 Xcode 的“属性检查器”中,向下滚动到“视图”部分并向下滚动 3 个空格(Xcode 11、Swift 5),您将看到一个名为“标签”的字段。为该集合视图分配一个整数值,然后对将嵌入到 UITableView 单元格中的每个集合视图重复此过程。 将所有集合视图标记为唯一整数后,您只需将案例设置为整数,并为每个 dequeueReusableCell 标识符提供与您在情节提要中提供的相同整数索引。

现在,当您在 TableViewCell 类中导出的 collectionView 上调用 tableView 单元格时,它将能够获取正确的 dequeueReusable ID。您可以将数据放入每个开关盒中。

瞧,您现在拥有一个 collectionView 数据源集所需的方法,但服务于您的所有集合视图。甚至更好的是,当有人扩展项目并添加另一个 collectionView 时,它就像在情节提要中的开关和标识符中添加另一个案例一样简单。

示例代码如下所示:

        // I need a switch statement which will set the correct (of the 3 collectionViews) dequeueReusable IDENTIFIER for the collectionView
    switch collectionView.tag 
        //if tableView is doing cell == 1, then "CatsCell"
        //if ...                cell == 3, then "DogsCell"
        //if ...                cell == 5, then "BirdsCell"
    case 1:
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CatsCell", for: indexPath) as! CatsCVCell
        // put your required data here
        return cell
    case 3:
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DogCell", for: indexPath) as! DogsCVCell
        // example data
        let dogs = dogController.fetch()
        cell.name = dogs[indexPath.item].dogName
        if let image = UIImage(data: groups[indexPath.item].image!) 

            cell.image = image
        
        return cell
    case 5:
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BirdCell", for: indexPath) as! BirdCVCell
        // put data code here for birds collection view cells
        return cell
    default:
        return UICollectionViewCell()  // or write a fatalError()
    

注意:对于 switch 语句的默认设置,您有两个选项... 1. 像上面一样,一个通用但为空的单元格实例 2.抛出错误。该错误永远不会抛出,因为您将遇到所有情况,但是如果其他人改进了您的代码并添加了另一个 collectionView 但忘记添加 switch case,则可能会发生错误-因此请让您的错误语句准确地解释问题所在。

【讨论】:

以上是关于为啥两个表格视图单元格中的两个集合视图在 Swift 4 中不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

将两个单独的Firebase节点中的数据加载到一个表格视图单元格中

表格视图单元格中的文本字段

表格视图单元格中的 uicollectionview 出现错误:索引超出范围,为啥?

为啥表格视图单元格中的自动布局会导致表格的内容大小被错误地更改?

表格单元格中的集合视图。这是重用的错误

如何在不丢失表格视图单元格的情况下将现有集合视图添加到表格视图