¿Cómo puedo comprobar si un indexPath es válido, evitando así un error de "intento de desplazarse a una ruta de índice no válida"?


¿Cómo puedo comprobar si un indexPath es válido o no?

Quiero desplazarme a una ruta de índice, pero a veces recibo un error si las subviews de mi vista de colección no han terminado de cargarse.

Author: webmagnets, 2015-04-08

7 answers

Usted podría comprobar

- numberOfSections
- numberOfItemsInSection: 

De su UICollection​View​Data​Source para ver si su indexPath es válido.

 24
Author: muffe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-27 09:05:49

¿Una solución más concisa?

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

O más compacto, pero menos legible...

func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
    return indexPath.section < numberOfSectionsInCollectionView(collectionView) && indexPath.row < collectionView.numberOfItemsInSection(indexPath.section)
}
 12
Author: Andres Canella,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-26 17:24:19

La respuesta de@ABakerSmith está cerca, pero no del todo correcta.

La respuesta depende de tu modelo.

Si tiene una vista de colección de varias secciones (o una vista de tabla para el caso, el mismo problema), entonces es bastante común usar una matriz de matrices para guardar sus datos.

La matriz externa contiene sus secciones, y cada matriz interna contiene las filas para esa sección.

Así que podrías tener algo como esto:

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

En ese caso, cuando se presenta con un indexPath, tendría que interrogar su objeto modelo (myTableViewData, en el ejemplo anterior)

El código podría verse así:

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
}

EDITAR:

@ABakerSmith tiene un giro interesante: Preguntar a la fuente de datos. De esta manera puede escribir una solución que funcione independientemente del modelo de datos. Su código está cerca, pero aún no es del todo correcto. Realmente debería ser esto:

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
}
 10
Author: Duncan C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 05:31:12

Aquí hay un fragmento de Swift 4 que escribí y he estado usando durante un tiempo. Le permite desplazarse a un indexPath solo si está disponible, o-lanzar un error si el indexPath no está disponible, para permitirle controlar lo que desea hacer en esta situación.

Echa un vistazo al código aquí:

Https://gist.github.com/freak4pc/0f244f41a5379f001571809197e72b90

Te permite hacer lo siguiente:

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

O

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

Este último lanzaría algo como:

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

 3
Author: Shai Mishali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-18 09:41:53

Usando la extensión 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
Author: Ashok Kumar S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-21 08:59:42

Si está intentando establecer el estado de una celda en la vista de colección sin saber si la ruta del índice es válida o no, podría intentar guardar los índices para celdas con un estado especial y establecer el estado de las celdas mientras las carga.

 0
Author: carrotzoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-28 16:01:09

Tal vez esto es lo que estás buscando?

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

Valor devuelto: El objeto cell en la ruta de índice correspondiente o nil si la celda no es visible o indexPath está fuera de rango.

 -3
Author: Thorory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-11 02:37:06