【问题标题】:PHFetchOptions for PHAsset in same sort order as Photos.appPHAsset 的 PHFetchOptions 与 Photos.app 的排序顺序相同
【发布时间】:2015-03-13 00:09:37
【问题描述】:

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

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

【问题讨论】:

  • 您使用了我的答案还是想出了另一个答案?如果是,请接受我的回答。

标签: ios objective-c swift photokit


【解决方案1】:

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

// 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”将获得默认值。您可以重新排序相机胶卷中的图像,此代码将反映更改。

【讨论】:

    【解决方案2】:

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

    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 中完全相同的流顺序。

    希望对您有所帮助。 :]

    【讨论】:

    • 如果您正在观察更改将无法工作[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver...
    • 为什么不呢?只需确保从 photoLibraryDidChange: 方法重新加载主线程上的数据
    • 嘿,这个解决方案在某些情况下似乎是错误的。我通过使用相机胶卷智能相册想出了一个有效的相册,您可能会发现这很有用(github.com/Athlee/ATHKit/blob/master/Source/…)。看看fetchResult 是如何设置的。 ;] 虽然您必须获取具有反向索引的资产,因为它返回集合,其中 0th 资产是您相机胶卷中的第一个资产,等等。
    【解决方案3】:

    跟进@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()
            }
    
            ...
    
        }
    }
    

    【讨论】:

      【解决方案4】:

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

      这解决了在这个问题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)];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-10
        • 1970-01-01
        • 1970-01-01
        • 2021-08-28
        • 1970-01-01
        • 1970-01-01
        • 2012-02-14
        相关资源
        最近更新 更多