Подтвердить что ты не робот

Как я могу проверить, является ли indexPath действительным, избегая при этом ошибки "попытка прокрутки до неверного пути индекса"?

Как я могу проверить, является ли indexPath действительным или нет?

Я хочу перейти к indexPath, но иногда я получаю сообщение об ошибке, если мои UICollectionView не завершают загрузку.

4b9b3361

Ответ 1

Вы можете проверить

- numberOfSections
- numberOfItemsInSection: 

вашего UICollection​View​Data​Source, чтобы узнать, является ли ваш indexPath допустимым.

Ответ 2

Более сжатое решение?

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)
}

Ответ 3

Ответ @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
}

EDIT:

@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
}

Ответ 4

Вот фрагмент кода Swift 4, который я написал и какое-то время использовал. Он позволяет вам либо прокрутить 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]

Ответ 5

Используя быстрое расширение:

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)
}

Ответ 6

Если вы пытаетесь установить состояние ячейки в представлении коллекции, не зная, допустим ли путь индекса, вы можете попытаться сохранить индексы для ячеек с особым состоянием и установить состояние ячеек при их загрузке.

Ответ 7

Версия C:

- (BOOL)indexPathIsValid:(NSIndexPath *)indexPath
{
    return indexPath.section < [self.collectionView numberOfSections] && indexPath.row < [self.collectionView numberOfItemsInSection:indexPath.section];
}

Ответ 8

Вы должны проверить правильность путей индекса, которые будут добавлены к источнику данных (будущее состояние), и удаление путей индекса с текущими существующими (текущее состояние).

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

Ответ 9

Возможно, это то, что вы ищете?

- (UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath

Возвращаемое значение: Объект ячейки по соответствующему пути индекса или nil, если ячейка не видна, или indexPath выходит за допустимые пределы.