How do I get a list of all collections, including the camera roll (which is now called moments), in iOS8?
In iOS 7, I use ALAssetGroup enumeration block, but that doesn't include iOS moments which is seems to be equivalent to Camera Roll in iOS7.
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
{
if (group == nil) {// We're done enumerating
return;
}
[group setAssetsFilter:[ALAssetsFilter allAssets]];
if ([[sGroupPropertyName lowercaseString] isEqualToString:@"camera roll"] && nType == ALAssetsGroupSavedPhotos) {
[_assetGroups insertObject:group atIndex:0];
} else {
[_assetGroups addObject:group];
}
};
// Group Enumerator Failure Block
void (^assetGroupEnumberatorFailure)(NSError *) = ^(NSError *error) {
SMELog(@"Enumeration occured %@", [error description]);
};
// Enumerate Albums
[_library enumerateGroupsWithTypes:kSupportedALAlbumsMask
usingBlock:assetGroupEnumerator
failureBlock:assetGroupEnumberatorFailure];
}];
Using Photos Framework is a bit different, you can achieve the same result though, you just have to do it in parts.
1) Get all photos (Moments in iOS8, or Camera Roll before)
PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
Optionally if you want them ordered as by creation date, you just add PHFetchOptions
like so:
PHFetchOptions *allPhotosOptions = [PHFetchOptions new];
allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:allPhotosOptions];
Now if you want you can get assets from the PHFetchResult
object:
[allPhotosResult enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
NSLog(@"asset %@", asset);
}];
2) Get all user albums (with additional sort for example to only show albums with at least one photo)
PHFetchOptions *userAlbumsOptions = [PHFetchOptions new];
userAlbumsOptions.predicate = [NSPredicate predicateWithFormat:@"estimatedAssetCount > 0"];
PHFetchResult *userAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:userAlbumsOptions];
[userAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) {
NSLog(@"album title %@", collection.localizedTitle);
}];
For each PHAssetCollection
that is returned from PHFetchResult *userAlbums
you can fetch PHAssets
like so (you can even limit results to include only photo assets):
PHFetchOptions *onlyImagesOptions = [PHFetchOptions new];
onlyImagesOptions.predicate = [NSPredicate predicateWithFormat:@"mediaType = %i", PHAssetMediaTypeImage];
PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:onlyImagesOptions];
3) Get smart albums
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
[smartAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) {
NSLog(@"album title %@", collection.localizedTitle);
}];
One thing to note with Smart Albums is that collection.estimatedAssetCount
can return NSNotFound
if estimatedAssetCount cannot be determined. As title suggest this is estimated. If you want to be sure of number of assets you have to perform fetch and get the count like:
PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
number of assets = assetsFetchResult.count
Apple has a sample project that does what you want:
https://developer.apple.com/library/content/samplecode/UsingPhotosFramework/ExampleappusingPhotosframework.zip (you have to be a registered developer to access this)
This is simply a translation of @Ladislav's superb accepted answer into Swift:
// *** 1 ***
// Get all photos (Moments in iOS8, or Camera Roll before)
// Optionally if you want them ordered as by creation date, you just add PHFetchOptions like so:
let allPhotosOptions = PHFetchOptions()
allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
let allPhotosResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: allPhotosOptions)
// Now if you want you can get assets from the PHFetchResult object:
allPhotosResult.enumerateObjectsUsingBlock({ print("Asset \($0.0)") })
// *** 2 ***
// Get all user albums (with additional sort for example to only show albums with at least one photo)
let userAlbumsOptions = PHFetchOptions()
userAlbumsOptions.predicate = NSPredicate(format: "estimatedAssetCount > 0")
let userAlbums = PHAssetCollection.fetchAssetCollectionsWithType(PHAssetCollectionType.Album, subtype: PHAssetCollectionSubtype.Any, options: userAlbumsOptions)
userAlbums.enumerateObjectsUsingBlock({
if let collection = $0.0 as? PHAssetCollection {
print("album title: \(collection.localizedTitle)")
//For each PHAssetCollection that is returned from userAlbums: PHFetchResult you can fetch PHAssets like so (you can even limit results to include only photo assets):
let onlyImagesOptions = PHFetchOptions()
onlyImagesOptions.predicate = NSPredicate(format: "mediaType = %i", PHAssetMediaType.Image.rawValue)
if let result = PHAsset.fetchKeyAssetsInAssetCollection(collection, options: onlyImagesOptions) {
print("Images count: \(result.count)")
}
}
})
// *** 3 ***
// Get smart albums
let smartAlbums = PHAssetCollection.fetchAssetCollectionsWithType(.SmartAlbum, subtype: .AlbumRegular, options: nil) // Here you can specify Photostream, etc. as PHAssetCollectionSubtype.xxx
smartAlbums.enumerateObjectsUsingBlock( {
if let assetCollection = $0.0 as? PHAssetCollection {
print("album title: \(assetCollection.localizedTitle)")
// One thing to note with Smart Albums is that collection.estimatedAssetCount can return NSNotFound if estimatedAssetCount cannot be determined. As title suggest this is estimated. If you want to be sure of number of assets you have to perform fetch and get the count like:
let assetsFetchResult = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: nil)
let numberOfAssets = assetsFetchResult.count
let estimatedCount = (assetCollection.estimatedAssetCount == NSNotFound) ? -1 : assetCollection.estimatedAssetCount
print("Assets count: \(numberOfAssets), estimate: \(estimatedCount)")
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With