6

我正在使用新的 PHFetchOptions 的 sortDescriptors 从相机胶卷中获取 PHAsset。似乎只有两个键可以排序:creationDate 和 modifyDate,这两个键都与您在 Photos.app 中看到的不同。

我错过了什么吗?我们怎样才能让它发挥作用?

4

4 回答 4

7

我使用以下代码获取包含“相机胶卷”的智能相册列表:

// get the smart albums
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
for (NSInteger i = 0; i < smartAlbums.count; i++) {
    PHAssetCollection *assetCollection = smartAlbums[i];
    // Then use the following to get the photo images:
    PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
    }

默认排序顺序是集合中资产的现有顺序,包括“相机胶卷”。为选项传递“nil”将获得默认值。您可以重新排序相机胶卷中的图像,此代码将反映更改。

于 2015-04-29T16:12:50.687 回答
3

有一个超级简单的解决方案。

  1. 创建没有任何特定选项的提取结果。

    // ...
    
    let options = PHFetchOptions()
    fetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: options)
    
    if fetchResult.count > 0 {
      collectionView.reloadData()
    }
    
    // ...
    
  2. 当您尝试加载某个资产时,只需使用反向索引。

    // ...
    
    let reversedIndex = fetchResult.count - indexPath.item - 1
    let asset = fetchResult[reversedIndex] as! PHAsset
    
    // ...
    

这样,您将获得与 Photo.app 中完全相同的流顺序。

希望对您有所帮助。:]

于 2016-07-14T03:17:33.930 回答
1

跟进@Majotron 的回答,我想按照All Photos照片应用程序中的相册的确切顺序获取所有用户的照片,并且只使用图像资产。

这是我设置我的方式PHFetchOptions

let allPhotosOption = PHFetchOptions()
// Fetch only image asset
allPhotosOption.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)
// Get All Photos album collection
let userLibrary = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil).firstObject
allPhotosResult = PHAsset.fetchAssets(in: userLibrary!, options: allPhotosOption)

并使用 TableView/CollectionView 中的反向索引获取特定资产:

let asset = allPhotosResult.object(at: allPhotosResult.count - indexPath.item - 1)

如果您正在收听照片库更改并相应地重新排列您的视图,也要小心。当更改与删除相关时,使用更改前的获取结果获取反向索引,.fetchResultAfterChanges否则使用。

这是我的处理方式:

func photoLibraryDidChange(_ changeInstance: PHChange) {

    ... 

    DispatchQueue.main.sync {
        let originalCount = fetchResult.count
        fetchResult = changes.fetchResultAfterChanges
        if changes.hasIncrementalChanges {

            guard let collectionView = self.collectionView else { return }

            collectionView.performBatchUpdates({

                if let removed = changes.removedIndexes, removed.count > 0 {
                    collectionView.deleteItems(at: removed.map({ IndexPath(item: originalCount - $0 - 1, section: 0) }))
                }
                if let inserted = changes.insertedIndexes, inserted.count > 0 {
                    collectionView.insertItems(at: inserted.map({ IndexPath(item: fetchResult.count - $0 - 1, section: 0) }))
                }
            })
            // Avoid deleting and reloading same index path at one update
            collectionView.performBatchUpdates({
                if let changed = changes.changedIndexes, changed.count > 0 {
                    collectionView.reloadItems(at: changed.map({ IndexPath(item: fetchResult.count - $0 - 1, section: 0) }))
                }
                changes.enumerateMoves { fromIndex, toIndex in
                    collectionView.moveItem(at: IndexPath(item: fetchResult.count - $0 - 1, section: 0),
                                            to: IndexPath(item: fetchResult.count - $0 - 1, section: 0))
                }
            })

        } else {
            collectionView!.reloadData()
        }

        ...

    }
}
于 2019-06-15T14:16:46.137 回答
0

我知道这是一个老问题,但我认为分享一个有效的答案会很有用。

这解决了在这个问题中被收购PHFetchOptions for PHAsset in same sort order as Photos.app并在 iOS 13 中工作的问题。

PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
PHFetchResult<PHAssetCollection *> *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
PHFetchResult<PHAsset *> *allPhotos = [PHAsset fetchAssetsInAssetCollection:smartAlbums.firstObject options:allPhotosOptions];

而已。请记住,顺序是最新的图像/视频最后,所以如果您想首先显示最新的图像/视频(如我们需要的那样),请使用

[allPhotos objectAtIndex:(allPhotos.count - 1 - indexPath.item)];
于 2020-07-02T10:22:45.197 回答