在Swift [Faster Way?]中基于creationDate从图库中获取所有照片。

时间:2018-11-01 09:22:57

标签: swift phasset photosframework phassetslibrary

我有一个props.onChange(param.val);根据最新的“ creationDate”显示图书馆照片。为此,我正在使用以下代码:

{ return props.onChange(param.val); }

该代码运行良好!但是问题在于,加载10k +照片需要花费几乎7-9秒的时间。直到6k张照片都没有问题,但是我真的需要一些有效的方法,以便可以将UICollectionView中的某些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) } 加载到其中,其余的可以稍后添加。无论照片数多少,我都需要不超过2-3秒。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

假设您有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,这些看似很小,但我只是想提供帮助:)