2

I want the user to have the ability to access all of their photos, but loading them all at once takes too long using PHAsset.fetchAssetsInAssetCollection, especially if they have 500+ photos (I am displaying them in a collection view in a custom-built view). I was thinking about using scrollViewDidScroll when the user reaches the end of the collection view to load the next set, but I do not know how to get the next x amount from the photo library.

I limited the amount of photos they can get using fetchOptions.fetchLimit = x, but I don't know how to tell the function where to begin fetching the assets. Is it possible?

Here is a snippet of my current code (the assetCollections is set in a different part of the code):

let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: kFormatOfPredicate, PHAssetMediaType.Image.rawValue)
fetchOptions.sortDescriptors = [NSSortDescriptor(key: kSortByCreationDateString, ascending: false)]
fetchOptions.fetchLimit = 32

//Only want camera roll
if assetCollection.localizedTitle == kCameraRollString {
assets = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: fetchOptions)
if assets.count > 32 {
    for i in 0..<32 {
        if let asset = assets[i] as? PHAsset {
            appendImageArray(assetToBeChanged: asset)
        }
    }
} else {
    for i in 0..<assets.count {
        if let asset = assets[i] as? PHAsset {
            appendImageArray(assetToBeChanged: asset)
        }
    }
}

is there something I can add to my fetchOptions to say which assets to start getting? Is there a better way entirely to do this? Let me know if you need me to post more code, and thank you in advance!

Kiley
  • 409
  • 1
  • 5
  • 19

2 Answers2

0

I have an idea of how you can achieve this:

  • When the first bunch of the fetched assets is scrolled down you should obtain the creationDate of the first asset. Suppose you will do it like this:

    let firstAsset = assets[0] as! PHAsset
    // The first asset date will be used when scrolling up.
    firstAssetDate = firstAsset.creationDate
    
  • Now to fetch another bunch of assets you configure the fetch options using your current sort descriptors (to sort in descending date order):

    fetchOptions.sortDescriptors = [NSSortDescriptor(key: kSortByCreationDateString, ascending: false)] 
    

    and the following predicate (to fetch only the most recent assets in accordance with the current last asset date):

    let lastAsset = assets[assets.count - 1] as! PHAsset
    fetchOptions.predicate = NSPredicate(format: "(mediaType == %d) AND (creationDate < %@)", PHAssetMediaType.Image.rawValue, lastAsset.creationDate)
    
  • At this point you can clear the previous group of assets. If the user scrolls up - use the saved firstAssetDate in conjunction with the next predicate:

    fetchOptions.predicate = NSPredicate(format: "(mediaType == %d) AND (creationDate <= %@)", PHAssetMediaType.Image.rawValue, firstAssetDate) 
    

    If the user scrolls down - use the creationDate of the last asset in the current fetched array and the < comparison in the predicate.

Of course, this is just an abstract idea, but, I think, it can be easily implemented in conjunction with your current code.

Also don't forget about using PHCachingImageManager to improve scrolling performance.

Stan Mots
  • 1,193
  • 2
  • 15
  • 16
0

You can refer to Apple WWDC Demo code:

Example app using Photo framework

It demonstrates how to deal if the user scroll all the photos.

In this code example, it has a 'preheat' area where it is larger than the visible area, it will caching ahead and stop caching behind. And it calculate and maintain the 'preheat' range as the scroll happens. then it uses startCachingImages and stopCachingImages APIs. So you'll always have the data at hand.

The most useful function for you such are in this AssetGridViewController file

XueYu
  • 2,355
  • 29
  • 33