避免使用 PHAsset 获取图片时出现重复问题

8
在iOS 8上,我想获取存储在设备上的所有图片。问题是我确实得到了它们,但有些出现了重复。对于所有图片,PHAsset属性(hidden、mediaSubtypes等)都是相同的,所以例如我不能排除PHAssetMediaSubtypePhotoHDR子类型。我找到的唯一方法是不添加创建日期相同的多张图片,但当多张照片保存在同一日期时,这就成了一个问题。
有人知道为什么会出现这些重复,并且我能做些什么来避免它们吗?
以下是我获取图片的方式:
    PHFetchOptions *fetchOptions = [PHFetchOptions new];
    fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES],];
    PHFetchResult *phAssets = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions];

这些重复项是指向同一张图片还是仅仅在视觉上相似? - Scott
它们指向的是视觉上相同的不同图片。它们的 "creationDate" 可以相同或显示出微不足道的差异。 - olivier
1
它们听起来像爆发声。参见下面的答案。 - Clay Bridges
5个回答

6
自从iOS 8.1版本以后,fetchAssetsWithMediaType:fetchAssetsWithOptions: 方法的行为已经改变,它们不再包括从iTunes同步到设备上的照片或存储在iCloud共享照片流中的照片。
来源:文档修订历史PHAsset 类参考文档

我感到震惊——真的很震惊!发现两个苹果链接都失效了。我正在积极调查此事,并真诚地希望能看到这一说法的文档或支持材料。 - Clay Bridges
1
@ClayBridges:第二个链接指向苹果的PHAsset类参考。如果您展开fetchAssetsWithMediaType:options:方法文档,您可以在讨论部分中阅读以下注意事项:重要提示 - 如果此方法由iOS 8.1或之后版本链接的应用程序调用,则结果不包括从iTunes同步到设备的照片或存储在iCloud共享照片流中的照片。 - Rufel

5
你可以尝试使用“朋友圈收藏”功能:
PHFetchResult * moments = [PHAssetCollection fetchMomentsWithOptions:nil];            
for (PHAssetCollection * moment in moments) {
    PHFetchResult * assetsFetchResults = [PHAsset fetchAssetsInAssetCollection:moment options:nil];
    for (PHAsset * asset in assetsFetchResults) {
        //Do something with asset, for example add them to array
    }
}

@TapanThaker - 它花费时间在哪里?是仅仅获取PHAsset并将其放入数组中,还是做了其他事情?我很快也会研究这个问题。 - BlueVoodoo
只需要将它放到一个数组中。 - Tapan Thaker
1
这是我使用的避免重复的方法。我有大约5k张照片和250个视频,它可以在不到一秒钟的时间内完成。你是否打印了很多东西或者做了一些浪费的事情?我的问题是PHAssetCollections是不可变的,所以你必须使用NSMutableArray,但这与新的照片通知不太兼容。 - VaporwareWolf
也许我错了,但是当我尝试使用for循环遍历时刻(moment)时,编译器会报错说时刻不是连续类型。我使用enumerateObjectsUsingBlock解决了这个问题。 - Lachezar Todorov
实现后,重复项比以前更多。 - Lachezar Todorov
显示剩余2条评论

3

我曾经遇到过同样的问题,对我来说,重复的图片是存在于我的相片流相册中的。为了解决这个问题,我现在使用PHAssetCollection类中的FetchMoments方法,然后获取每个时刻的所有资源。这样我就可以获取到所有的图片而不会重复。

如果有人找到更好的解决方案,请告诉我。


非常感谢您的回答。您和Ponf的回答似乎同时出现且相似。我不得不做出选择,并将他的回答标记为最佳答案,因为尽管您的解释更好,但他包含了可工作的代码,这可能会更快地帮助到遇到同样问题的人们。 - olivier
是的,这也是我一直在使用的。它运行良好,仍然可以获取iCloud照片。 - VaporwareWolf

0
在传单上,这些资源是否是爆发的一部分?(参见 PHAsset.burstIdentifier 等)。如果是,您可以进行相应的调整。

0
你可以使用“PHImageRequestOptions”来设置只获取高质量的图片!
//Setting up the deliveryMode in PHImageRequestOptions()
fileprivate func imageRequestOptions() -> PHImageRequestOptions {
    let requestOption = PHImageRequestOptions()
    requestOption.deliveryMode = .highQualityFormat
    return requestOption
}

fileprivate func fetchImages(){

    let fetchOptions = assetsFetchOptions() //get fetchOptions only. Don`t worry
    let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)

    allPhotos.enumerateObjects({ (asset, index, stop) in
        print(asset)

        let imageManager = PHImageManager.default()
        let targetSize = CGSize(width: 200, height: 200)

        //This function uses the "imageRequestOptions()" function to set up the "options:" field in this .requestImage() function.
        imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: self.imageRequestOptions(), resultHandler: { (image, info) in

            if let image = image {
                self.images.append(image)
                self.assets.append(asset)

                if self.selectedImage == nil {
                    self.selectedImage = image
                }
            }

            if index == allPhotos.count - 1 {
                self.collectionView?.reloadData()
            }
        })
    })
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接