Question

j'ai un UICollectionView dans lequel j'essaie d'y insérer des éléments de manière dynamique/avec animation.J'ai donc une fonction qui télécharge des images de manière asynchrone et j'aimerais insérer les éléments par lots.

Une fois que j'ai mes données, j'aimerais faire ce qui suit :

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

Maintenant à la place du ***, je devrais passer un tableau de NSIndexPaths, qui doit indiquer l'emplacement des nouveaux éléments à insérer.Je suis très confus car après avoir fourni l'emplacement, comment puis-je fournir l'image réelle qui doit être affichée à cette position ?

Merci


MISE À JOUR:

resultsSize contient la taille du tableau de la source de données, self.results, avant que de nouvelles données ne soient ajoutées à partir des données à 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];
Était-ce utile?

La solution

Voir Insertion, suppression et déplacement de sections et d'éléments du "Guide de programmation de la vue Collection pour iOS":

Pour insérer, supprimer ou déplacer une seule section ou élément, vous devez suivre ces étapes:

  1. Mettez à jour les données dans votre objet source de données.
  2. Appelez la méthode appropriée de la vue de collection pour insérer ou supprimer la section ou l'élément.

Il est essentiel que vous mettiez à jour votre source de données avant de notifier la vue de collecte de toute modification.Les méthodes de vue de collecte supposent que votre source de données contient les données actuellement correctes.Si ce n'est pas le cas, la vue de la collection peut recevoir le mauvais ensemble d'éléments de votre source de données ou demander des éléments qui ne sont pas là et écraser votre application.

Donc, dans votre cas, vous devez d'abord ajouter une image à la source de données de la vue de collection, puis appeler insertItemsAtIndexPaths.La vue de collection demandera ensuite à la fonction déléguée de la source de données de fournir la vue de l'élément inséré.

Autres conseils

Je viens de l'implémenter avec Swift.Je voudrais donc partager ma mise en œuvre.Initialisez d’abord un tableau de NSBlockOperations :

    var blockOperations: [NSBlockOperation] = []

Le contrôleur va changer, réinitialisez le tableau :

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

Dans la méthode objet did change :

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

Dans la méthode de section did change :

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

Et enfin, dans le contrôleur did, la méthode de contenu a été modifiée :

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

J'ai personnellement ajouté du code dans la méthode deinit, afin d'annuler les opérations lorsque le ViewController est sur le point d'être désalloué :

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

    blockOperations.removeAll(keepCapacity: false)
}

J'étais confronté au même problème lors de la suppression de l'élément de l'index et c'est ce que je pense que nous devons faire lors de l'utilisation performBatchUpdates: méthode.

1# appelez d’abord deleteItemAtIndexPath pour supprimer l’élément de la vue collection.

2# Supprimez l'élément du tableau.

3# Mettre à jour la vue de la collection en rechargeant les données.

[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];
        }];

Cela m'aide à supprimer tous les crashs et échecs d'assertion.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top