I have a UICollectionView
displaying library photos based on latest "creationDate". For that I am using below code:
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)
}
The code works nicely! But the problem is it takes almost 7 - 9 seconds to load 10k+ photos. Till 6k photos there is no problem, but I really need some efficient way so that I can load some of the asset
in UICollectionView
and rest of them I can add later. I need that no matter the photos count, it should not take more than 2 - 3 seconds. Can anybody please help?
Let's say you have 8k photos. So you iterate through two 'for' loops in order to get the arrCreationDate and arrPhotoAssets data(which is double the work needed)
Instead, you can try doing it through a single loop. Here's a rough way:-
This is just for you to get a rough idea of what I'm talking about, as this will reduce half the burden(just a single loop)
Also try using prefetchDataSource for your collection view to preload it with some data
EDIT:-
I assume that you have tried the following already:-
If this doesn't help, how about reloading the collection view with some kind of callback after every loop iteration? (with the above approach) This way, you won't make the user wait until the whole thing gets loaded
Idk, these might look petty but I'm just trying to help :)