基于 Swift 中的 creationDate 从库中获取所有照片 [更快的方式?]
Posted
技术标签:
【中文标题】基于 Swift 中的 creationDate 从库中获取所有照片 [更快的方式?]【英文标题】:Fetch All Photos from Library based on creationDate in Swift [Faster Way?] 【发布时间】:2018-11-01 09:22:56 【问题描述】:我有一个UICollectionView
显示基于最新“creationDate”的图书馆照片。为此,我使用以下代码:
struct AssetsData
var creationDate: Date, assetResult: PHFetchResult<PHAsset>
func fetchPhotos() -> [AssetsData]
//Date Formatter
let formatter = DateFormatter()
formatter.dateStyle = DateFormatter.Style.medium
formatter.timeStyle = DateFormatter.Style.none
//Photos fetch
let fetchOptions = PHFetchOptions()
let sortOrder = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.sortDescriptors = sortOrder
let assetsFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
var arrCreationDate = [Date]()
var arrDates = [String]()
//Getting All dates
for index in 0..<assetsFetchResult.count
if let creationDate = assetsFetchResult[index].creationDate
let formattedDate = formatter.string(from: creationDate)
if !arrDates.contains(formattedDate)
arrDates.append(formattedDate)
arrCreationDate.append(creationDate)
//Fetching Assets based on Dates
var arrPhotoAssetsData = [AssetsData]()
for createdDate in arrCreationDate
if let startDate = getDate(forDay: createdDate.day, forMonth: createdDate.month, forYear: createdDate.year, forHour: 0, forMinute: 0, forSecond: 0), let endDate = getDate(forDay: createdDate.day, forMonth: createdDate.month, forYear: createdDate.year, forHour: 23, forMinute: 59, forSecond: 59)
fetchOptions.predicate = NSPredicate(format: "creationDate > %@ AND creationDate < %@", startDate as NSDate, endDate as NSDate)
let assetsPhotoFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
arrPhotoAssetsData.append(AssetsData(creationDate: createdDate, assetResult: assetsPhotoFetchResult))
return arrPhotoAssetsData
func getDate(forDay day: Int, forMonth month: Int, forYear year: Int, forHour hour: Int, forMinute minute: Int, forSecond second: Int) -> Date?
var dateComponents = DateComponents()
dateComponents.day = day
dateComponents.month = month
dateComponents.year = year
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.second = second
var gregorian = Calendar(identifier: Calendar.Identifier.gregorian)
gregorian.timeZone = NSTimeZone.system
return gregorian.date(from: dateComponents)
代码运行良好!但问题是加载 10k+ 张照片需要将近 7 - 9 秒。直到 6k 张照片都没有问题,但我真的需要一些有效的方法,以便我可以在 UICollectionView
中加载一些 asset
,其余的我可以稍后添加。我需要无论照片数量如何,都不应超过 2 - 3 秒。有人可以帮忙吗?
【问题讨论】:
【参考方案1】:假设您有 8k 张照片。因此,您遍历两个“for”循环以获取 arrCreationDate 和 arrPhotoAssets 数据(这是所需工作的两倍)
相反,您可以尝试通过一个循环来完成。这是一个粗略的方法:-
let assetsFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
let fetchOptions = PHFetchOptions()
var arrCreationDate = [Date]()
var arrPhotoAssetsData = [AssetsData]()
var arrDates = [String]()
for index in 0..<assetsFetchResult.count
if let creationDate = assetsFetchResult[index].creationDate
let formattedDate = formatter.string(from: creationDate)
if !arrDates.contains(formattedDate)
//You can convert the formattedDate to actual date here and do a check similar to this, do what you do in the other loop here too
if(actualDate < actualDateOfTheFirstElementAtArray)
arrCreationDate.insert(actualDate, at: 0)
fetchOptions.predicate = NSPredicate(format: "creationDate > %@ AND creationDate < %@", startDate as NSDate, endDate as NSDate)
let assetsPhotoFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
arrPhotoAssetsData.insert(AssetsData(creationDate: createdDate, assetResult: assetsPhotoFetchResult), at: 0)
这只是为了让您大致了解我在说什么,因为这样可以减轻一半的负担(只需一个循环)
还可以尝试使用 prefetchDataSource 为您的集合视图预加载一些数据
编辑:-
我假设您已经尝试过以下方法:-
func fetchPhotos() -> [AssetsData]
//Date Formatter
let formatter = DateFormatter()
formatter.dateStyle = DateFormatter.Style.medium
formatter.timeStyle = DateFormatter.Style.none
//Photos fetch
let fetchOptions = PHFetchOptions()
let sortOrder = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.sortDescriptors = sortOrder
let assetsFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
var arrCreationDate = [Date]()
var arrDates = [String]()
var arrPhotoAssetsData = [AssetsData]()
//Getting All dates
for index in 0..<assetsFetchResult.count
if let creationDate = assetsFetchResult[index].creationDate
let formattedDate = formatter.string(from: creationDate)
if !arrDates.contains(formattedDate)
arrDates.append(formattedDate)
arrCreationDate.append(creationDate)
convertToAssetsDataAndAppend(date: creationDate, fetchOptions: fetchOptions, toArray: &arrPhotoAssetsData)
return arrPhotoAssetsData
func convertToAssetsDataAndAppend(date: Date, fetchOptions: PHFetchOptions, toArray: inout [AssetsData])
if let startDate = getDate(forDay: date.day, forMonth: date.month, forYear: date.year, forHour: 0, forMinute: 0, forSecond: 0), let endDate = getDate(forDay: date.day, forMonth: date.month, forYear: date.year, forHour: 23, forMinute: 59, forSecond: 59)
fetchOptions.predicate = NSPredicate(format: "creationDate > %@ AND creationDate < %@", startDate as NSDate, endDate as NSDate)
let assetsPhotoFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
toArray.append(AssetsData(creationDate: date, assetResult: assetsPhotoFetchResult))
func getDate(forDay day: Int, forMonth month: Int, forYear year: Int, forHour hour: Int, forMinute minute: Int, forSecond second: Int) -> Date?
var dateComponents = DateComponents()
dateComponents.day = day
dateComponents.month = month
dateComponents.year = year
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.second = second
var gregorian = Calendar(identifier: Calendar.Identifier.gregorian)
gregorian.timeZone = NSTimeZone.system
return gregorian.date(from: dateComponents)
如果这没有帮助,那么在每次循环迭代后使用某种回调重新加载集合视图怎么样? (使用上述方法) 这样,您不会让用户等到整个内容加载完毕
Idk,这些可能看起来很琐碎,但我只是想帮忙:)
【讨论】:
谢谢。我试过了,但仍然需要 2.09 秒才能获取 3.1k 张照片,而我的需要 1.85 秒。 酷,所以你在当前的 for 循环中使用了另一个循环来对元素进行排序?在这种情况下,它是一个嵌套循环,显然会比通常的两个单独循环消耗更多时间。您可以做的是尝试使用二进制搜索进行排序 嗯..二进制搜索不会像我想的那样有效,因为没有搜索特定日期。我们需要根据从库中获取的日期的所有数据。你怎么看? 不,我明白了,但我认为您采用的方法类似于我的想法,我的错。我已经编辑了答案。让我知道你的想法... 所以你只是区分了附加部分!太酷了,我会尝试这种方式,比如附加前 5 或 6 个日期,然后重新加载UICollectionView
,然后再次附加新数据重新加载它。以上是关于基于 Swift 中的 creationDate 从库中获取所有照片 [更快的方式?]的主要内容,如果未能解决你的问题,请参考以下文章
如何在 sanity.io 中为文档创建默认的“creationDate”?