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

21

Как проверить, действителен ли indexPath или нет?

Я хочу прокручивать путь к указателю, но иногда получаю сообщение об ошибке, если вложенные объекты моего представления коллекции не закончены.

    
задан webmagnets 08.04.2015 в 15:51
источник

6 ответов

21

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

- numberOfSections
- numberOfItemsInSection: 

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

    
ответ дан muffe 08.04.2015 в 16:06
источник
9

@ Ответ 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
}
    
ответ дан Duncan C 08.04.2015 в 16:24
источник
9

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

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)
}
    
ответ дан Andres Canella 17.11.2016 в 22:57
источник
  • этот работает для меня –  Patel Jigar 21.12.2016 в 10:43
2

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

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)
}
    
ответ дан Ashok Kumar S 21.03.2018 в 09:59
источник
1

Вот фрагмент Swift 4, который я написал и использовал некоторое время. Он позволяет либо прокручивать IndexPath только в том случае, если он доступен, либо - выдавать ошибку, если IndexPath недоступен, чтобы вы могли контролировать то, что хотите сделать в этой ситуации.

Ознакомьтесь с кодом здесь:

Ссылка

Он также позволяет:

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]     

ответ дан Shai Mishali 18.01.2018 в 10:41
источник
-3

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

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

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

    
ответ дан Thorory 08.04.2015 в 16:24
источник
  • Это не сработает, потому что оно вернет nil, если indexPath существует в вашей модели данных, но в настоящее время не отображается на экране. –  Duncan C 08.04.2015 в 16:25
  • Я думал, что это проблема, а именно, что элемент существует (в модели), но не закончил отображение. –  Thorory 08.04.2015 в 17:23
  • Хм. Возможно, ты прав. Это не совсем ясно из вопроса ОП. Другая возможность - просто сделать явный вызов reloadData сразу после смены модели. –  Duncan C 08.04.2015 в 17:31