web-dev-qa-db-fra.com

Comment puis-je vérifier si un indexPath est valide, évitant ainsi une erreur "tentative de défilement vers un chemin d'index invalide"?

Comment puis-je vérifier si un indexPath est valide ou non?

Je souhaite faire défiler jusqu'à un chemin d'index, mais je reçois parfois une erreur si le chargement des sous-vues de ma collection est terminé.

26
webmagnets

Tu pourrais vérifier

- numberOfSections
- numberOfItemsInSection: 

de votre UICollection​View​Data​Source pour voir si votre indexPath est valide.

30
muffe

Une solution plus concise?

func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
    if indexPath.section >= numberOfSectionsInCollectionView(collectionView) {
        return false
    }
    if indexPath.row >= collectionView.numberOfItemsInSection(indexPath.section) {
        return false
    }
    return true
}

ou plus compact, mais moins lisible ...

func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
    return indexPath.section < numberOfSectionsInCollectionView(collectionView) && indexPath.row < collectionView.numberOfItemsInSection(indexPath.section)
}
16
Andres Canella

La réponse de @ ABakerSmith est proche, mais pas tout à fait raison.

La réponse dépend de votre modèle. 

Si vous avez une vue de collection à plusieurs sections (ou une vue de table - le même problème), il est assez courant d'utiliser un tableau de tableaux pour sauvegarder vos données.

Le tableau externe contient vos sections et chaque tableau interne contient les lignes de cette section.

Donc, vous pourriez avoir quelque chose comme ça:

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

Dans ce cas, lorsqu'un indexPath vous est présenté, vous devez interroger votre objet modèle (myTableViewData, dans l'exemple ci-dessus).

Le code pourrait ressembler à ceci:

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
}

MODIFIER:

@ABakerSmith a une tournure intéressante: Demander la source de données. De cette façon, vous pouvez écrire une solution qui fonctionne quel que soit le modèle de données. Son code est proche, mais pas encore tout à fait correct. Ça devrait vraiment être ça:

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
}
11
Duncan C

Voici un extrait de Swift 4 que j'ai écrit et que j'utilise depuis longtemps. Il vous permet de faire défiler jusqu'à IndexPath uniquement s'il est disponible ou - émettez une erreur si IndexPath n'est pas disponible pour vous permettre de contrôler ce que vous voulez faire dans cette situation. 

Découvrez le code ici:

https://Gist.github.com/freak4pc/0f244f41a5379f001571809197e72b90

Il vous permet de faire soit:

myCollectionView.scrollToItemIfAvailable(at: indexPath, at: .top, animated: true)

Ou 

myCollectionView.scrollToItemOrThrow(at: indexPath, at: .top, animated: true)

Ce dernier lancerait quelque chose comme: 

expression unexpectedly raised an error: IndexPath [0, 2000] is not available. The last available IndexPath is [0, 36]

4
Shai Mishali

Utilisation de l'extension Swift:

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)
}
3
Ashok Kumar S

Si vous essayez de définir l'état d'une cellule dans la vue de collection sans savoir si le chemin d'index est valide ou non, vous pouvez essayer de sauvegarder les index des cellules avec un état spécial et de définir l'état des cellules lors du chargement.

0
carrotzoe