Pregunta

tengo un UICollectionView que estoy intentando insertar elementos dinámicamente/con animación.Tengo alguna función que descarga imágenes de forma asincrónica y me gustaría insertar los elementos en lotes.

Una vez que tenga mis datos, me gustaría hacer lo siguiente:

[self.collectionView performBatchUpdates:^{
    for (UIImage *image in images) {
        [self.collectionView insertItemsAtIndexPaths:****]
    }
} completion:nil];

Ahora en lugar del ***, debería pasar una serie de NSIndexPaths, que debe señalar la ubicación de los nuevos elementos que se insertarán.Estoy muy confundido ya que después de proporcionar la ubicación, ¿cómo proporciono la imagen real que debería mostrarse en esa posición?

Gracias


ACTUALIZAR:

resultsSize contiene el tamaño de la matriz de origen de datos, self.results, antes de que se agreguen nuevos datos a partir de los datos en newImages.

[self.collectionView performBatchUpdates:^{

    int resultsSize = [self.results count];
    [self.results addObjectsFromArray:newImages];
    NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];

    for (int i = resultsSize; i < resultsSize + newImages.count; i++)
          [arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];

          [self.collectionView insertItemsAtIndexPaths:arrayWithIndexPaths];

} completion:nil];
¿Fue útil?

Solución

Ver Insertar, eliminar y mover secciones y elementos desde el "Guía de programación de vista de colección para iOS":

Para insertar, eliminar o mover una sola sección o elemento, debe seguir estos pasos:

  1. Actualice los datos en su objeto de fuente de datos.
  2. Llame al método apropiado de la vista de colección para insertar o eliminar la sección o elemento.

Es fundamental que actualice su fuente de datos antes de notificar la vista de recopilación de cualquier cambio.Los métodos de vista de recopilación suponen que su fuente de datos contiene los datos actualmente correctos.Si no es así, la vista de recopilación puede recibir el conjunto incorrecto de elementos de su fuente de datos o solicitar elementos que no estén allí y bloqueen su aplicación.

Entonces, en su caso, primero debe agregar una imagen a la fuente de datos de la vista de colección y luego llamar insertItemsAtIndexPaths.Luego, la vista de la colección solicitará a la función delegada de la fuente de datos que proporcione la vista para el elemento insertado.

Otros consejos

Lo acabo de implementar con Swift.Entonces me gustaría compartir mi implementación.Primero inicialice una serie de NSBlockOperations:

    var blockOperations: [NSBlockOperation] = []

En el controlador cambiará, reinicie la matriz:

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    blockOperations.removeAll(keepCapacity: false)
}

En el método de objeto cambió:

    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {

    if type == NSFetchedResultsChangeType.Insert {
        println("Insert Object: \(newIndexPath)")

        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.insertItemsAtIndexPaths([newIndexPath!])
                }
            })
        )
    }
    else if type == NSFetchedResultsChangeType.Update {
        println("Update Object: \(indexPath)")
        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.reloadItemsAtIndexPaths([indexPath!])
                }
            })
        )
    }
    else if type == NSFetchedResultsChangeType.Move {
        println("Move Object: \(indexPath)")

        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.moveItemAtIndexPath(indexPath!, toIndexPath: newIndexPath!)
                }
            })
        )
    }
    else if type == NSFetchedResultsChangeType.Delete {
        println("Delete Object: \(indexPath)")

        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.deleteItemsAtIndexPaths([indexPath!])
                }
            })
        )
    }
}

En el método de la sección cambió:

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {

    if type == NSFetchedResultsChangeType.Insert {
        println("Insert Section: \(sectionIndex)")

        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.insertSections(NSIndexSet(index: sectionIndex))
                }
            })
        )
    }
    else if type == NSFetchedResultsChangeType.Update {
        println("Update Section: \(sectionIndex)")
        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.reloadSections(NSIndexSet(index: sectionIndex))
                }
            })
        )
    }
    else if type == NSFetchedResultsChangeType.Delete {
        println("Delete Section: \(sectionIndex)")

        blockOperations.append(
            NSBlockOperation(block: { [weak self] in
                if let this = self {
                    this.collectionView!.deleteSections(NSIndexSet(index: sectionIndex))
                }
            })
        )
    }
}

Y finalmente, en el método del controlador cambió el contenido:

func controllerDidChangeContent(controller: NSFetchedResultsController) {        
    collectionView!.performBatchUpdates({ () -> Void in
        for operation: NSBlockOperation in self.blockOperations {
            operation.start()
        }
    }, completion: { (finished) -> Void in
        self.blockOperations.removeAll(keepCapacity: false)
    })
}

Personalmente también agregué algo de código en el método deinit para cancelar las operaciones cuando el ViewController está a punto de ser desasignado:

deinit {
    // Cancel all block operations when VC deallocates
    for operation: NSBlockOperation in blockOperations {
        operation.cancel()
    }

    blockOperations.removeAll(keepCapacity: false)
}

Me enfrenté a un problema similar al eliminar el elemento del índice y esto es lo que creo que debemos hacer mientras usamos performBatchUpdates: método.

1# primero llame a deleteItemAtIndexPath para eliminar el elemento de la vista de colección.

2# Eliminar el elemento de la matriz.

3# Actualizar la vista de colección recargando datos.

[self.collectionView performBatchUpdates:^{
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:sender.tag inSection:0];
            [self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
            [self.addNewDocumentArray removeObjectAtIndex:sender.tag];
        } completion:^(BOOL finished) {
            [self.collectionView reloadData];
        }];

Esto me ayuda a eliminar todos los fallos de aserción y bloqueo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top