PHAsset 的 PHFetchOptions 排序顺序与 Photos.app 相同
PHFetchOptions for PHAsset in same sort order as Photos.app
我正在使用新的 PHFetchOptions 的 sortDescriptors 从相机胶卷中获取 PHAssets。似乎只有两个键可以排序:creationDate 和 modificationDate,这两个键都与您在 Photos.app.
中看到的相同
我错过了什么吗?我们怎样才能让它发挥作用?
我已使用以下代码获取智能相册列表,其中包括 "Camera Roll":
// 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];
}
默认排序顺序是集合中资产的现有顺序,包括 "Camera Roll"。为选项传递 "nil" 获取默认值。您可以重新排列相机胶卷中的图像,此代码将反映更改。
有一个超级简单的解决方案。
创建不带任何特定选项的抓取结果。
// ...
let options = PHFetchOptions()
fetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: options)
if fetchResult.count > 0 {
collectionView.reloadData()
}
// ...
当您尝试加载某个资产时,只需使用反向索引即可。
// ...
let reversedIndex = fetchResult.count - indexPath.item - 1
let asset = fetchResult[reversedIndex] as! PHAsset
// ...
这样您将获得与 Photo.app 中完全相同的流程顺序。
希望对您有所帮助。 :]
跟进@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 - [=12=] - 1, section: 0) }))
}
if let inserted = changes.insertedIndexes, inserted.count > 0 {
collectionView.insertItems(at: inserted.map({ IndexPath(item: fetchResult.count - [=12=] - 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 - [=12=] - 1, section: 0) }))
}
changes.enumerateMoves { fromIndex, toIndex in
collectionView.moveItem(at: IndexPath(item: fetchResult.count - [=12=] - 1, section: 0),
to: IndexPath(item: fetchResult.count - [=12=] - 1, section: 0))
}
})
} else {
collectionView!.reloadData()
}
...
}
}
我知道这是一个老问题,但我认为分享一个可行的答案会很有用。
这解决了在这个问题 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];
就是这样。请记住,顺序是最新的 image/video 最后,所以如果你想首先显示最新的 image/video (正如我们需要的那样)然后使用
[allPhotos objectAtIndex:(allPhotos.count - 1 - indexPath.item)];
我正在使用新的 PHFetchOptions 的 sortDescriptors 从相机胶卷中获取 PHAssets。似乎只有两个键可以排序:creationDate 和 modificationDate,这两个键都与您在 Photos.app.
中看到的相同我错过了什么吗?我们怎样才能让它发挥作用?
我已使用以下代码获取智能相册列表,其中包括 "Camera Roll":
// 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];
}
默认排序顺序是集合中资产的现有顺序,包括 "Camera Roll"。为选项传递 "nil" 获取默认值。您可以重新排列相机胶卷中的图像,此代码将反映更改。
有一个超级简单的解决方案。
创建不带任何特定选项的抓取结果。
// ... let options = PHFetchOptions() fetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: options) if fetchResult.count > 0 { collectionView.reloadData() } // ...
当您尝试加载某个资产时,只需使用反向索引即可。
// ... let reversedIndex = fetchResult.count - indexPath.item - 1 let asset = fetchResult[reversedIndex] as! PHAsset // ...
这样您将获得与 Photo.app 中完全相同的流程顺序。
希望对您有所帮助。 :]
跟进@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 - [=12=] - 1, section: 0) }))
}
if let inserted = changes.insertedIndexes, inserted.count > 0 {
collectionView.insertItems(at: inserted.map({ IndexPath(item: fetchResult.count - [=12=] - 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 - [=12=] - 1, section: 0) }))
}
changes.enumerateMoves { fromIndex, toIndex in
collectionView.moveItem(at: IndexPath(item: fetchResult.count - [=12=] - 1, section: 0),
to: IndexPath(item: fetchResult.count - [=12=] - 1, section: 0))
}
})
} else {
collectionView!.reloadData()
}
...
}
}
我知道这是一个老问题,但我认为分享一个可行的答案会很有用。
这解决了在这个问题 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];
就是这样。请记住,顺序是最新的 image/video 最后,所以如果你想首先显示最新的 image/video (正如我们需要的那样)然后使用
[allPhotos objectAtIndex:(allPhotos.count - 1 - indexPath.item)];