iOS 8 Photos 框架:使用 iOS8 获取所有相册的列表

Posted

技术标签:

【中文标题】iOS 8 Photos 框架:使用 iOS8 获取所有相册的列表【英文标题】:iOS 8 Photos framework: Get a list of all albums with iOS8 【发布时间】:2014-09-22 19:04:54 【问题描述】:

如何在 ios8 中获取所有收藏的列表,包括相机胶卷(现在称为时刻)?

在 iOS 7 中,我使用 ALAssetGroup 枚举块,但这不包括 iOS 时刻,这似乎相当于 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];
    ];

【问题讨论】:

【参考方案1】:

使用 Photos Framework 有点不同,但你可以达到相同的结果,你只需要部分地做。

1) 获取所有照片(iOS8 中的 Moments 或之前的相机胶卷)

PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];

如果您希望它们按创建日期排序,您只需添加PHFetchOptions,如下所示:

PHFetchOptions *allPhotosOptions = [PHFetchOptions new];
allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:allPhotosOptions];

现在,如果您愿意,您可以从 PHFetchResult 对象获取资产:

[allPhotosResult enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) 
    NSLog(@"asset %@", asset);
];

2) 获取所有用户相册(通过附加排序,例如仅显示包含至少一张照片的相册)

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);
];

对于从PHFetchResult *userAlbums 返回的每个PHAssetCollection,您可以像这样获取PHAssets(您甚至可以将结果限制为仅包含照片资产):

PHFetchOptions *onlyImagesOptions = [PHFetchOptions new];
onlyImagesOptions.predicate = [NSPredicate predicateWithFormat:@"mediaType = %i", PHAssetMediaTypeImage];
PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:onlyImagesOptions];

3) 获取智能相册

PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
[smartAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) 
        NSLog(@"album title %@", collection.localizedTitle);
];

使用智能相册需要注意的一点是,如果无法确定estimateAssetCount,collection.estimatedAssetCount 可以返回NSNotFound。正如标题所示,这是估计的。如果您想确定资产的数量,您必须执行 fetch 并获得如下计数:

PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];

资产数量 = assetsFetchResult.count

Apple 有一个示例项目可以满足您的需求:

https://developer.apple.com/library/content/samplecode/UsingPhotosFramework/ExampleappusingPhotosframework.zip(您必须是注册开发者才能访问)

【讨论】:

嘿@Ladislav,很好的答案。但是您怎么知道使用creationDate 作为 sortDescriptor,照片属性是否记录在任何地方? Apple 有一个非常好的文档 - developer.apple.com/library/prerelease/ios/documentation/Photos/… 看看 sortDescriptors,你会看到:“用你想要获取的照片实体的属性构造排序描述符,列出在表 1 中。例如,以下代码按创建日期排序以查找照片库中最旧的资产。表 1 包含可用于 PHAsset、PHAssetCollection、PHCollectionList、PHCollection...的所有属性... 谢谢。正是我想要的! @Ladislav 感谢您的出色回答。我不明白为什么您需要获取“所有照片”。我意识到它在示例应用程序中执行此操作,但如果您获取智能相册和相册,它不会覆盖所有照片吗? 我试图获取所有照片,但它不包括 Moments 中的照片(它只包括相机胶卷)。不确定它与 iOS 9 有什么关系。我还尝试了 Apple 示例代码,虽然他们说它包含时刻,但它没有。【参考方案2】:

这只是将@Ladislav 出色的公认答案翻译成 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)")
    
)

【讨论】:

非常感谢! 嗨@Grimxn,我想知道,如何仅在照片库中获取最后导入的照片。基于创建日期排序,我们也得到了所有的图像。但我的要求是只获取最后导入的照片。因为,我们使用外接相机拍摄照片并复制到 IPAD。那么,如何在应用端获取“上次导入的照片”? 我目前不在处理这个问题,但我想您需要枚举资产集合https://developer.apple.com/documentation/photos/phassetcollection#1656287 并检查它们的assetCollectionTypes...【参考方案3】:

试试这个代码...

self.imageArray=[[NSArray alloc] init];

PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init];
requestOptions.resizeMode   = PHImageRequestOptionsResizeModeExact;
requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
requestOptions.synchronous = true;
PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];

NSLog(@"%d",(int)result.count);

    PHImageManager *manager = [PHImageManager defaultManager];
    NSMutableArray *images = [NSMutableArray arrayWithCapacity:countValue];

    // assets contains PHAsset objects.

    __block UIImage *ima;
    for (PHAsset *asset in result) 
        // Do something with the asset

        [manager requestImageForAsset:asset
                           targetSize:PHImageManagerMaximumSize
                          contentMode:PHImageContentModeDefault
                              options:requestOptions
                        resultHandler:^void(UIImage *image, NSDictionary *info) 
                            ima = image;

                            [images addObject:ima];

                        ];




    self.imageArray = [images copy];

【讨论】:

以上是关于iOS 8 Photos 框架:使用 iOS8 获取所有相册的列表的主要内容,如果未能解决你的问题,请参考以下文章

如何使用照片框架在 IOS 8 中将照片添加到照片库

iOS8.0 使用Photos.framework对相册的常用操作

PHAsset,如何在应用重启后检索特定的 PHAsset 对象(ios8 Photos)

iOS开发进阶 - 基于PhotoKit的图片选择器

在 iOS 8 中编辑照片:允许“YourApp”修改这张照片?

iOS 8 动态框架:未加载库