2015-05-29 45 views
5

Tôi biết rằng có đã là câu hỏi này trên SO, nhưng tôi không nghĩ rằng câu trả lời được đưa ra là thỏa mãn/hoàn thành: How can IOS Photos app can show hundreds of photos in one screen?Làm thế nào để sử dụng PHCachingImageManager

Những gì tôi muốn đạt được

tôi muốn một cái gì đó giống như lựa chọn hình ảnh trong whatsapp (iOS) (xem ảnh chụp màn hình). Khi bạn mở máy ảnh, cũng có thanh trượt ngang, nơi bạn có thể xem tất cả hình ảnh từ thư viện của mình.

whatsapp screenshot

Những gì tôi cố gắng

Ngay bây giờ tôi có đoạn mã sau vào appdelegate tôi:

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

Sau đó tôi tải các hình ảnh trong một UITableViewController và gọi hàm sau trên cuộn:

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

} 

Điều này hoạt động tốt nhưng tôi có vấn đề là trên mỗi ứng dụng bắt đầu tất cả các tài sản của tôi được lưu trữ. Đây có phải là cách tiếp cận đúng cho vấn đề của tôi không? Làm thế nào tôi có thể hiển thị các thư viện ảnh trong thời gian thực như whatsapp?

+0

Tại sao bạn muốn nội dung khi bạn có thể tìm lại chúng? Lưu trữ chúng có thể phức tạp vì một số nội dung có thể đã bị xóa/thêm/sửa đổi sau khi ứng dụng của bạn bị giết. Ngoài ra bạn không phải lấy tất cả chúng một lần nữa. Bạn chỉ cần tìm nạp những thứ bạn cần để hiển thị người dùng trên màn hình tại thời điểm đó. Một số bối cảnh về nhu cầu lưu trữ chúng sẽ giúp ích cho bạn. – jarora

+0

@jarora Tôi đã chỉnh sửa toàn bộ câu hỏi của mình, cung cấp mã và ví dụ tôi muốn đạt được. –

Trả lời

3

Tham khảo Photos Framework example Trong dự án này, bạn nên xem xét tệp AAPLAssetGridViewController.m và cách nó xử lý bộ nhớ đệm dựa trên vị trí cuộn của bạn.

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

Trình quản lý bộ nhớ đệm hình ảnh làm nóng nội dung mong muốn của bạn và sau đó bạn có thể truy xuất chúng từ chính trình quản lý lưu trữ hình ảnh.

Hy vọng nó sẽ giúp bạn.

+0

Xin chào, tôi đang sử dụng mã của bạn trong ứng dụng của tôi và dòng 'PHAsset * asset = self.assetsFetchResults [indexPath.item]; 'ném ngoại lệ sau cho tôi:' *** Chấm dứt ứng dụng do ngoại lệ không bị bắt' NSRangeException ' , lý do: '0x1957a880: index (0) vượt quá giới hạn (0)' 'Điều này không xảy ra mỗi lần, tức là tôi biết về ngoại lệ này từ HockeyApp. Bất kỳ ý tưởng gì có thể gây ra điều này? – Banana

+0

Tôi cũng đã nhận được ngoại lệ tương tự như vậy nhưng tôi đã không thể để lý do đằng sau nó. Cách giải quyết duy nhất tôi biết là thêm séc: indexPath.item jarora

Các vấn đề liên quan