2015-05-29 9 views
5

Ich weiß, dass es bereits diese Frage auf SO, aber ich glaube nicht, dass die gegebene Antwort befriedigend/Abschluss: How can IOS Photos app can show hundreds of photos in one screen?So verwenden PHCachingImageManager

Was ich

ich erreichen will Ich möchte etwas wie die Bildauswahl in WhatsApp (iOS) (siehe Screenshot). Wenn Sie die Kamera öffnen, gibt es auch einen horizontalen Schieberegler, wo Sie alle Bilder aus Ihrer Galerie sehen können.

whatsapp screenshot

Was habe ich versucht,

Im Moment habe ich den folgenden Code in meinem AppDelegate haben:

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

Später lade ich die Bilder in einem UITableViewController und rufen Sie die folgende Funktion auf scrollen:

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

} 

Das funktioniert gut, aber ich habe das Problem, dass bei jedem Start alle meine Assets zwischengespeichert werden. Ist das der richtige Ansatz für mein Problem? Wie kann ich die Galerie-Fotos in Echtzeit wie WhatsApp anzeigen?

+0

Warum möchten Sie die Vermögenswerte, wenn Sie sie wieder abrufen können? Das Speichern dieser Dateien kann knifflig sein, da einige Assets nach dem Absturz Ihrer App möglicherweise gelöscht/hinzugefügt/geändert wurden. Auch müssen Sie nicht alle von ihnen wieder holen. Sie sollten nur diejenigen holen, die Sie benötigen, um den Benutzer zu diesem Zeitpunkt auf dem Bildschirm zu zeigen. Ein gewisser Zusammenhang über die Notwendigkeit, sie zu speichern, würde helfen. – jarora

+0

@jarora Ich habe meine ganze Frage bearbeitet, Code und ein Beispiel, das ich erreichen möchte. –

Antwort

3

Verweise Photos Framework example In diesem Projekt sollten Sie in die Datei AAPLAssetGridViewController.m schauen und wie es Caching basierend auf Ihrer Bildlaufposition behandelt.

- (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; 
    } 

Das Bild Caching-Manager heizt mit Ihrem Vermögen der gewünschten Größe und dann können Sie sie aus dem Abbild-Cache-Manager abrufen selbst.

Ich hoffe, es hilft Ihnen.

+0

Hallo, ich benutze Ihren Code in meiner App und die Zeile 'PHAsset * asset = self.assetsFetchResults [indexPath.item];' löst die folgende Ausnahme aus: '*** Beenden der App aufgrund der nicht abgefangenen Ausnahme 'NSRangeException' , Grund: '0x1957a880: Index (0) über Grenzen (0)' 'Das passiert nicht jedes Mal, dh ich kenne diese Ausnahme von HockeyApp. Irgendeine Idee was könnte das verursachen? – Banana

+0

Nun, ich habe ähnliche Ausnahmen bekommen, aber ich war nicht in der Lage, den Grund dafür zu finden. Die einzige Problemumgehung, die ich kenne, ist das Hinzufügen der Überprüfung: indexPath.item jarora