【发布时间】:2015-06-13 12:41:02
【问题描述】:
如何检查indexPath 是否有效?
我想滚动到indexPath,但如果我的UICollectionView 子视图未完成加载,有时会出现错误。
【问题讨论】:
标签: ios swift uicollectionview nsindexpath
如何检查indexPath 是否有效?
我想滚动到indexPath,但如果我的UICollectionView 子视图未完成加载,有时会出现错误。
【问题讨论】:
标签: ios swift uicollectionview nsindexpath
你可以检查
- numberOfSections
- numberOfItemsInSection:
您的UICollectionViewDataSource 以查看您的 indexPath 是否有效。
例如
extension UICollectionView {
func isValid(indexPath: IndexPath) -> Bool {
guard indexPath.section < numberOfSections,
indexPath.row < numberOfItems(inSection: indexPath.section)
else { return false }
return true
}
}
【讨论】:
EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff8) numberOfRows :/(我用于表格视图,但我认为这个概念是一样的?)
也许这就是你要找的东西?
- (UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath
返回值: 对应索引路径处的单元格对象,如果单元格不可见或 indexPath 超出范围,则为 nil。
【讨论】:
reloadData。
@ABakerSmith 的回答很接近,但并不完全正确。
答案取决于您的型号。
如果您有一个多节集合视图(或表视图 - 同样的问题),那么使用数组数组来保存数据是很常见的。
外部数组包含您的部分,每个内部数组包含该部分的行。
所以你可能会有这样的事情:
struct TableViewData
{
//Dummy structure, replaced with whatever you might use instead
var heading: String
var subHead: String
var value: Int
}
typealias RowArray: [TableViewData]
typeAlias SectionArray: [RowArray]
var myTableViewData: SectionArray
在这种情况下,当出现 indexPath 时,您需要询问您的模型对象(myTableViewData,在上面的示例中)
代码可能如下所示:
func indexPathIsValid(theIndexPath: NSIndexPath) -> Bool
{
let section = theIndexPath.section!
let row = theIndexPath.row!
if section > myTableViewData.count-1
{
return false
}
let aRow = myTableViewData[section]
return aRow.count < row
}
@ABakerSmith 有一个有趣的转折点:询问数据源。这样,您就可以编写一个不管数据模型如何都可以工作的解决方案。他的代码很接近,但仍然不太正确。真的应该是这样的:
func indexPathIsValid(indexPath: NSIndexPath) -> Bool
{
let section = indexPath.section!
let row = indexPath.row!
let lastSectionIndex =
numberOfSectionsInCollectionView(collectionView) - 1
//Make sure the specified section exists
if section > lastSectionIndex
{
return false
}
let rowCount = self.collectionView(
collectionView, numberOfItemsInSection: indexPath.section) - 1
return row <= rowCount
}
【讨论】:
更简洁的解决方案?
func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
if indexPath.section >= numberOfSectionsInCollectionView(collectionView) {
return false
}
if indexPath.row >= collectionView.numberOfItemsInSection(indexPath.section) {
return false
}
return true
}
或更紧凑,但可读性较差...
func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
return indexPath.section < numberOfSectionsInCollectionView(collectionView) && indexPath.row < collectionView.numberOfItemsInSection(indexPath.section)
}
【讨论】:
这是我编写并使用了一段时间的 Swift 4 sn-p。 它允许您仅在 IndexPath 可用时滚动到 IndexPath,或者 - 如果 IndexPath 不可用则抛出错误,以让您控制在这种情况下要执行的操作。
在此处查看代码:
https://gist.github.com/freak4pc/0f244f41a5379f001571809197e72b90
它可以让你做到:
myCollectionView.scrollToItemIfAvailable(at: indexPath, at: .top, animated: true)
或者
myCollectionView.scrollToItemOrThrow(at: indexPath, at: .top, animated: true)
后者会抛出类似:
expression unexpectedly raised an error: IndexPath [0, 2000] is not available. The last available IndexPath is [0, 36]
【讨论】:
使用快速扩展:
extension UICollectionView {
func validate(indexPath: IndexPath) -> Bool {
if indexPath.section >= numberOfSections {
return false
}
if indexPath.row >= numberOfItems(inSection: indexPath.section) {
return false
}
return true
}
}
// Usage
let indexPath = IndexPath(item: 10, section: 0)
if sampleCollectionView.validate(indexPath: indexPath) {
sampleCollectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.centeredHorizontally, animated: true)
}
【讨论】:
如果您在不知道索引路径是否有效的情况下尝试在集合视图中设置单元格的状态,您可以尝试保存具有特殊状态的单元格的索引,并设置单元格的状态同时加载它们。
【讨论】:
Objective C 版本:
- (BOOL)indexPathIsValid:(NSIndexPath *)indexPath
{
return indexPath.section < [self.collectionView numberOfSections] && indexPath.row < [self.collectionView numberOfItemsInSection:indexPath.section];
}
【讨论】:
您应该检查将附加数据源的索引路径的验证(未来状态)以及删除当前现有索引路径的索引路径(当前状态)。
extension UITableView {
func isValid(indexPath: IndexPath, inDataSource: Bool = false) -> Bool {
guard
let numberOfSections = inDataSource
? dataSource?.numberOfSections?(in: self)
: numberOfSections,
let numberOfRows = inDataSource
? dataSource?.tableView(self, numberOfRowsInSection: indexPath.section)
: numberOfRows(inSection: indexPath.section)
else {
preconditionFailure("There must be a datasource to validate an index path")
}
return indexPath.section < numberOfSections && indexPath.row < numberOfRows
}
用法:
// insert
tableView.insertRows(at: indexPaths.filter({ tableView.isValid(indexPath: $0, inDataSource: true) }), with: .top)
// remove
tableView.deleteRows(at: indexPaths.filter({ tableView.isValid(indexPath: $0) }), with: .top)
输出:
true or false
【讨论】: