为啥两个表格视图单元格中的两个集合视图在 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 出现错误:索引超出范围,为啥?