1

我有一个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 张照片都没有问题,但我真的需要一些有效的方法,以便我可以加载其中的一些,asset其余UICollectionView的我可以稍后添加。我需要无论照片数量如何,都不应超过 2 - 3 秒。有人可以帮忙吗?

4

1 回答 1

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,这些可能看起来很琐碎,但我只是想帮忙:)

于 2018-11-01T11:03:37.123 回答