Como os filtros UIScrollView / UICollectionView no aplicativo Photos da Apple são implementados para abrir tão rápido?

Não estou perguntando sobre o código exato, mas a ideia geral.

Aqui está o meu problema: estou tentando criar algo semelhante ao filtro, escolhendo a interface do usuário no aplicativo Fotos. Eu tentei várias abordagens e todas elas têm suas desvantagens.

1) Eu tentei usarOperation eOperationQueue com uma exibição de coleção, cuja pré-busca está ativada. Isso carrega o viewController rapidamente, mas descarta os quadros durante a rolagem.

2) No momento, estou usando uma visualização de rolagem eGCD mas carrega o viewController por muito tempo (porque aplica todos os filtros a todos os botões dentro dele de uma só vez), mas depois rola suavemente.

NOTA: Para responder à pergunta, não há necessidade de ler a parte abaixo (acredito), no entanto, se você estiver interessado em saber como eu tento implementar a funcionalidade, leia-a.

Para a implementação de todos os filtros, eu uso uma estrutura chamadaFilters responsável por iniciar cada filtro e anexá-lo a uma matriz.

struct Filters {
var image: UIImage
var allFilters: [CIFilter] = []

init(image: UIImage) {

    self.image = image

    guard  let sepia = Sepia(image: image) else {return}

    allFilters.append(contentsOf: [sepia, sepia, sepia, sepia, sepia, sepia, sepia, sepia, sepia, sepia, sepia, sepia, sepia])

       }
  }

No momento, estou usando apenas um filtro.Sepia é uma subclasse deCIFilter. Eu o criei como uma subclasse, porque no futuro vou criar um personalizado a partir dele. Aqui está a sua implementação:

class Sepia: CIFilter {

var inputImage: CIImage?
var inputIntensity: NSNumber?

@objc override var filterName: String? {
    return NSLocalizedString("Sepia", comment: "Name of a Filter")
}

convenience init?(image: UIImage, inputIntensity: NSNumber? = nil) {
    self.init()

    guard let cgImage = image.cgImage else {
        return nil
    }

    if inputIntensity != nil {
        self.inputIntensity = inputIntensity
    } else {
        self.setDefaults()
    }

    let inputImage = CIImage(cgImage: cgImage)
    self.inputImage = inputImage
}

override func setDefaults() {
    inputIntensity = 1.0
}

override var outputImage: CIImage? {
    guard let inputImage = inputImage, let inputIntensity = inputIntensity else {
        return nil
    }

    let filter = CIFilter(name: "CISepiaTone", withInputParameters: [kCIInputImageKey: inputImage, kCIInputIntensityKey: inputIntensity])

   return filter?.outputImage

  }
}

No viewController'sviewDidLoad Eu inicioFilters struct:

self.filters = Filters(image: image)

Então eu chamo um método que configura algumas visualizações (filterViews) com base no número de filtros nofilters.allFilters matriz e itera sobre eles e chama um método que leva uma miniaturaUIImage e aplica um filtro a ele e o retorna em um manipulador de conclusão (eu usoDispatchGroup por razões de depuração). Aqui está o método que aplica um filtro a uma miniatura:

func imageWithFilter(filter: CIFilter, completion: @escaping(UIImage?)->Void) {

    let group = DispatchGroup()
    group.enter()
    DispatchQueue.global().async {
        guard let outputImage = filter.value(forKey: kCIOutputImageKey) as? CIImage, let cgImageResult = self.context.createCGImage(outputImage, from: outputImage.extent) else  {
            DispatchQueue.main.async {
                 completion(nil)
            }
            group.leave()
            return
        }

        let filteredImage = UIImage(cgImage: cgImageResult)
        DispatchQueue.main.async {
            print (filteredImage)
            completion(filteredImage)

        }

       group.leave()
    }

    group.notify(queue: .main) {
        print ("Filteres are set")
    }
}

A declaração de impressão acima e o endereço da imagem filtrada são impressos muito em breve, no entanto, as imagens não aparecem nas visualizações.

Eu tentei usarTime Profiler mas isso me dá alguns resultados estranhos. Por exemplo, mostra o seguinte como demorando muito para ser executado na raiz do backtrace:

Quando tento ver o código no Xcode, recebo o seguinte, o que não ajuda muito:

Então, esse é o problema. Se você tiver alguma idéia de como ele é implementado no aplicativo Fotos, é tão rápido e responsivo, ou se você tem sugestões sobre minha implementação, agradecemos sua ajuda.