8

In iOS PhotoKit, I can fetch all non-empty albums like this:

let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "estimatedAssetCount > 0")
let albumFetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: albumFetchOptions)

albumFetchResult.enumerateObjects({ (collection, _, _) in
    // Do something with the album...
})

Then I can get only photos from the album like this:

let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetResourceType.photo.rawValue)
let fetchResults = PHAsset.fetchAssets(in: collection, options: fetchOptions)

But the first part can give me albums with only videos, which means that after I apply the predicate to the second part, the album will be empty. Is there a way to filter out those albums in the first part, before I start using them?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Phlippie Bosman
  • 5,378
  • 3
  • 26
  • 29
  • Note: This question uses `PHAssetResourceType` as an argument where [`PHAssetMediaType`](https://developer.apple.com/documentation/photokit/phfetchoptions) is expected. `PHAssetResourceType.photo` and `PHAssetMediaType.image` both happen to have rawValue 1 but `PHAssetResourceType` is otherwise something different. – Arjan Dec 14 '22 at 15:31

1 Answers1

3

It seems that collections cannot be filtered like this without also fetching the items in the collections. See the docs for available fetch options; none allow filtering by number of a specific type of media.

The way I would achieve this is by fetching all albums created by the user, and then fetching the assets from the albums with a predicate that returns only images.

So to put it in code:

var userCollections: PHFetchResult<PHAssetCollection>!
// Fetching all PHAssetCollections with at least some media in it
let options = PHFetchOptions()
    options.predicate = NSPredicate(format: "estimatedAssetCount > 0")
// Performing the fetch
userCollections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: options)

Next, fetch the assets from a collection that are images by specifying a predicate:

// Getting the specific collection (I assumed to use a tableView)
let collection = userCollections[indexPath.row]
let optionsToFilterImage = PHFetchOptions()
    optionsToFilterImage.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Image.rawValue)
// Fetching the asset with the predicate to filter just images
let justImages = PHAsset.fetchAssets(in: collection, options: optionsToFilterImage)

Lastly, count the number of images:

if justImages.count > 0 {
    // Display it
} else {
    // The album has no images
}
Phlippie Bosman
  • 5,378
  • 3
  • 26
  • 29
Marco
  • 1,051
  • 1
  • 17
  • 40
  • it gives you just videos as result? the albumFetchResult constant is a collection of all the album created by the user... to fetch the single image you need to use PHImageManager... if you explain a little more what you are trying to achieve i'll try to help you out – Marco Oct 16 '17 at 07:50
  • To test this, I created an album that only contains videos. What I'm trying to achieve is for `albumFetchResult` to exclude such an album from its fetch results -- i.e. only albums with at least one photo should be included. Using `.albumRegular` as the subtype when fetching albums doesn't achieve that. – Phlippie Bosman Oct 16 '17 at 12:10
  • but then it works... basically you use the fetchresult with the predicate and then just control the result... if it's > than zero you display it els u don't... – Marco Oct 16 '17 at 12:46
  • Oh. Of course I could just fetch every PHAssetCollection and fetch all their items and count them. But my question is specifically concerned with filtering out albums with no photos *before* fetching all their items, so I can make use of Apple's optimized querying mechanism to provide a better user experience. Fetching everything is expensive and will leave the user waiting for things to load. – Phlippie Bosman Oct 16 '17 at 13:28
  • Honestly i'm not sure if there is another way... if you check on the apple docs u will see that the only predicate available for collection are: SELF, localIdentifier, localizedTitle (or title), startDate, endDate, estimatedAssetCount (https://developer.apple.com/documentation/photos/phfetchoptions). As far as i know this is the only way... but hopefully some one with more experience than me can help u! sorry... – Marco Oct 16 '17 at 14:36
  • This question has been up for a while with no other answers, so, unfortunately, you're probably right about there being no more efficient options. Would you consider editing your answer to reflect that? – Phlippie Bosman Oct 16 '17 at 15:18
  • 3
    @PhlippieBosman Hitting my head on this. There is indeed no other option to filter albums. Which is a shame since it's a very reasonable use-case (video app should only show albums with videos). Filtering my photo library with 15k assets, 200 albums takes 5 seconds. This needs to be repeated anytime the photo library updates. Users could have hundreds of thousands of assets which would leave them sitting there for a minute. Hilariously, in a WWDC video Apple warns Photos apps should be efficient and not let the user wait while items are being fetched. Well how? Back to UIImagePickerController? – tombardey Sep 05 '18 at 13:33