Pergunta

Eu tenho um UICollectionView o que eu estou tentando inserir itens em dinamicamente/com animação.Então, eu tenho alguma função que transfere imagens de forma assíncrona e gostaria de inserir os itens em lotes.

Assim que eu tiver os meus dados, eu gostaria de fazer o seguinte:

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

Agora, no lugar do ***, Eu deveria estar passando uma matriz de NSIndexPaths, que deve apontar para a localização dos novos itens a serem inseridos.Eu estou muito confuso, pois depois de fornecer a localização, como faço para fornecer a imagem real que deve ser exibido em que posição?

Obrigado


ATUALIZAÇÃO:

resultsSize contém o tamanho da fonte de dados matriz, self.results, antes de novos dados são adicionados a partir da data em 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];
Foi útil?

Solução

Ver Inserir, Excluir e Mover Seções e Itens a partir do "Coleção Visualizar o Guia de Programação para iOS":

Para inserir, excluir ou mover uma única seção ou item, você deve seguir estes passos:

  1. Atualizar os dados no seu objeto de fonte de dados.
  2. Chamar o método apropriado para a exibição de coleção para inserir ou excluir a seção ou item.

É fundamental que você atualize os seus dados de origem antes de notificar o vista de conjunto de todas as alterações.O modo de exibição de coleção de métodos de assumir se sua fonte de dados contém atualmente os dados corretos.Se ele faz não, a vista de conjunto pode receber o errado conjunto de itens a partir de a sua fonte de dados ou pedir para os itens que não estão lá e travar o seu app.

Então, no seu caso, você deve adicionar uma imagem à colecção de exibição de fonte de dados primeiro e, em seguida, chamar insertItemsAtIndexPaths.O modo de exibição de coleção, em seguida, irá pedir os dados de origem de função de delegação para fornecer a vista para o item inserido.

Outras dicas

Eu só implementado, que com o Swift.Então, eu gostaria de compartilhar a minha implementação.Primeiro inicializar uma matriz de NSBlockOperations:

    var blockOperations: [NSBlockOperation] = []

No controlador será alterado, re-inicialização da matriz:

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

Em o fez mudar de método do objeto:

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

Em o fez mudar de secção, método de:

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

E, finalmente, o fez controlador fez alterar o conteúdo do método:

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

Eu, pessoalmente, adicionou algum código no deinit método, bem como, para cancelar as operações quando o ViewController está prestes a ser liberada:

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

    blockOperations.removeAll(keepCapacity: false)
}

Eu estava enfrentando o problema semelhante ao eliminar o item do índice e é isso que eu acho que nós precisamos fazer ao usar os performBatchUpdates: o método.

1# primeira chamada deleteItemAtIndexPath para eliminar o item do modo de exibição de coleção.

2# Apagar o elemento de matriz.

3# Actualizar a colecção de vista de recarregar os dados.

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

Isso ajuda-me a remover todos os crash e falhas de asserção.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top