2015-05-29 19 views
5

So che c'è già a questa domanda su SO, ma non credo che la risposta fornita è soddisfacente/completo: How can IOS Photos app can show hundreds of photos in one screen?Come utilizzare PHCachingImageManager

Quello che voglio raggiungere

I vuoi qualcosa come la selezione dell'immagine in whatsapp (iOS) (vedi screenshot). Quando apri la videocamera, c'è anche un cursore orizzontale in cui puoi vedere tutte le immagini dalla tua galleria.

whatsapp screenshot

Quello che ho provato

In questo momento ho il seguente codice nel mio AppDelegate:

let options = PHFetchOptions() 

options.sortDescriptors = [ 
    NSSortDescriptor(key: "creationDate", ascending: true) 
] 
if let results = PHAsset.fetchAssetsWithMediaType(.Image, options: options) { 

    results.enumerateObjectsUsingBlock { (object, idx, _) in 
     if let asset = object as? PHAsset { 
      Variables.assets.append(asset) 
     } 
    } 

    println(Variables.assets.count) 

    Variables.imageManager.startCachingImagesForAssets(Variables.assets, targetSize: CGSizeMake(viewWidth, viewWidth), contentMode: .AspectFill, options: self.requestOptions) 
} 

Più tardi ho caricare le immagini in un UITableViewController e chiamare la seguente funzione su scroll:

func fetchPhotoAtIndex(index : Int) { 

    let asset = Variables.assets[Variables.assets.count - 1 - index] as PHAsset 

    Variables.imageManager.requestImageForAsset(asset, targetSize: CGSizeMake(self.viewWidth, self.viewWidth), contentMode: .AspectFill, options: self.requestOptions, resultHandler: { (image, _) in 

     println("\(asset.localIdentifier) \(asset.creationDate) ") 

     [...] 

     self.tableView.reloadData() 
    }) 

} 

Funziona bene, ma ho il problema che in ogni app tutte le mie risorse vengono messe in cache. È questo l'approccio giusto per il mio problema? Come posso visualizzare le foto della galleria in tempo reale come fa whatsapp?

+0

Perché vuoi le risorse quando puoi recuperarle di nuovo? Archiviarli può essere complicato in quanto alcune risorse potrebbero essere state eliminate/aggiunte/modificate dopo che la tua app è stata uccisa. Inoltre non devi recuperarli tutti di nuovo. Dovresti semplicemente recuperare quelli necessari per mostrare all'utente sullo schermo in quel momento. Un certo contesto sulla necessità di archiviarli aiuterebbe. – jarora

+0

@jarora Ho modificato la mia intera domanda, fornito codice e un esempio che voglio raggiungere. –

risposta

3

Consultare questo Photos Framework example In questo progetto è necessario esaminare il file AAPLAssetGridViewController.m e come gestisce la memorizzazione nella cache in base alla posizione di scorrimento.

- (void)updateCachedAssets 
     { 
      BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil; 
      if (!isViewVisible) { return; } 

      // The preheat window is twice the height of the visible rect 
      CGRect preheatRect = self.collectionView.bounds; 
      preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect)); 

      // If scrolled by a "reasonable" amount... 
      CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect)); 
      if (delta > CGRectGetHeight(self.collectionView.bounds)/3.0f) { 

       // Compute the assets to start caching and to stop caching. 
       NSMutableArray *addedIndexPaths = [NSMutableArray array]; 
       NSMutableArray *removedIndexPaths = [NSMutableArray array]; 

       [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) { 
        NSArray *indexPaths = [self.collectionView aapl_indexPathsForElementsInRect:removedRect]; 
        [removedIndexPaths addObjectsFromArray:indexPaths]; 
       } addedHandler:^(CGRect addedRect) { 
        NSArray *indexPaths = [self.collectionView aapl_indexPathsForElementsInRect:addedRect]; 
        [addedIndexPaths addObjectsFromArray:indexPaths]; 
       }]; 

       NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths]; 
       NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths]; 

       [self.imageManager startCachingImagesForAssets:assetsToStartCaching 
                targetSize:AssetGridThumbnailSize 
                contentMode:PHImageContentModeAspectFill 
                 options:nil]; 
       [self.imageManager stopCachingImagesForAssets:assetsToStopCaching 
                targetSize:AssetGridThumbnailSize 
                contentMode:PHImageContentModeAspectFill 
                 options:nil]; 

       self.previousPreheatRect = preheatRect; 
      } 
     } 
     //In your case this computeDifference method changes to handle horizontal scrolling 
      - (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler 
      { 
       if (CGRectIntersectsRect(newRect, oldRect)) { 
        CGFloat oldMaxY = CGRectGetMaxY(oldRect); 
        CGFloat oldMinY = CGRectGetMinY(oldRect); 
        CGFloat newMaxY = CGRectGetMaxY(newRect); 
        CGFloat newMinY = CGRectGetMinY(newRect); 
        if (newMaxY > oldMaxY) { 
         CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY)); 
         addedHandler(rectToAdd); 
        } 
        if (oldMinY > newMinY) { 
         CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY)); 
         addedHandler(rectToAdd); 
        } 
        if (newMaxY < oldMaxY) { 
         CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY)); 
         removedHandler(rectToRemove); 
        } 
        if (oldMinY < newMinY) { 
         CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY)); 
         removedHandler(rectToRemove); 
        } 
       } else { 
        addedHandler(newRect); 
        removedHandler(oldRect); 
       } 
      } 



- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths 
    { 
     if (indexPaths.count == 0) { return nil; } 

     NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count]; 
     for (NSIndexPath *indexPath in indexPaths) { 
      PHAsset *asset = self.assetsFetchResults[indexPath.item]; 
      [assets addObject:asset]; 
     } 
     return assets; 
    } 

L'immagine direttore di caching si scalda con le risorse della dimensione desiderata e poi li si può recuperare dall'immagine di cache manager stesso.

Spero che ti aiuti.

+0

Ciao, sto usando il tuo codice nella mia app e la riga 'PHAsset * asset = self.assetsFetchResults [indexPath.item];' genera per me la seguente eccezione: '*** Termina l'app a causa dell'eccezione non rilevata 'NSRangeException' , motivo: '0x1957a880: index (0) oltre limiti (0)' 'Questo non succede ogni volta, cioè so di questa eccezione da HockeyApp. Qualche idea di cosa potrebbe causare questo? – Banana

+0

Beh, anch'io ho riscontrato simili eccezioni, ma non sono riuscito a spiegarne il motivo. L'unica soluzione che so è aggiungere il controllo: indexPath.item jarora