从CloudKit获取CKAsset图像非常慢

Blu*_*ear 12 ios swift cloudkit

我正在使用CloudKit作为我的iOS应用程序的服务器后端.我用它来存放一些相对静态的数据以及一些图像(CKAsset).当我花时间从公共数据库中实际获取这些资产时,我遇到了一个问题.它们以极慢的速度加载.

我的用例是将图像加载到集合视图内的每个单元格中.图像的大小仅为200kb,但获取过程平均需要2.2秒才能完成下载并在单元格中设置图像.为了比较,我使用类似大小的库存图像的URL并使用NSURLSession加载它们.每个图像加载仅需0.18 - 0.25秒.

我尝试了多种不同的方式从CK下载图像:直接获取记录,查询和操作查询.所有这些都有类似的结果.在为单元格设置图像之前,我还将调度回完成块中的主队列.

我的数据库设置为具有包含多个数据字段的主对象.然后,我为照片设置了一个向后的参考样式系统,其中每张照片只有一个主要对象的引用.这样我就可以按需加载照片而不会影响主要数据.

它看起来像这样:

主要对象: title: String, startDate: Date

照片对象: owner: String(reference to primary object), image: Asset

以下是我尝试直接获取其中一张照片的示例请求:

let publicDb = CKContainer.defaultContainer().publicCloudDatabase
let configRecordId = CKRecordID(recordName: "e783f542-ec0f-46j4-9e99-b3e3ez505adf")

publicDb.fetchRecordWithID(configRecordId) { (record, error) -> Void in
    dispatch_async(dispatch_get_main_queue()) {
        guard let photoRecord = record else { return }
        guard let asset = photoRecord["image"] as? CKAsset else { return }

        guard let photo = NSData(contentsOfURL: asset.fileURL) else { return }

        let image = UIImage(data: photo)!

        cell.cardImageView.image = image
    }
}
Run Code Online (Sandbox Code Playgroud)

我似乎无法弄清楚为什么这些图像下载需要这么长时间,但如果我无法让它们在合理的时间内加载,那真的是非常明显的.

更新:我尝试使用较小的图像23kb进行获取操作.获取速度更快,从0.3到1.1秒不等.这更好,但仍然不符合我对CloudKit应该提供的期望.

Jef*_*ias 7

我正在使用CKQueryOperation.我发现,一旦我将以下代码添加到我的代码中,下载CKAssets的速度提高了大约5-10倍.

    queryOperation.qualityOfService = .UserInteractive
Run Code Online (Sandbox Code Playgroud)

这是我的完整代码:

func getReportPhotos(report:Report, completionHandler: (report:Report?, error:NSError?) -> ()) {
    let photo : Photo = report.photos![0] as! Photo
    let predicate : NSPredicate = NSPredicate(format: "recordID = %@", CKRecordID(recordName: photo.identifier!))
    let query : CKQuery = CKQuery(recordType: "Photo", predicate: predicate)
    let queryOperation : CKQueryOperation = CKQueryOperation()
    queryOperation.query = query
    queryOperation.resultsLimit = numberOfReportsPerQuery        
    queryOperation.qualityOfService = .UserInteractive
    queryOperation.recordFetchedBlock = { record in
        photo.date = record.objectForKey("date") as? NSDate
        photo.fileType = record.objectForKey("fileType") as? String
        let asset : CKAsset? = record.objectForKey("image") as? CKAsset
        if asset != nil {
            let photoData : NSData? = NSData(contentsOfURL:asset!.fileURL)
            let photo : Photo = report.photos![0] as! Photo
            photo.image = UIImage(data:photoData!)
        }

    }
    queryOperation.queryCompletionBlock = { queryCursor, error in
        dispatch_async(dispatch_get_main_queue(), {
            completionHandler(report: report, error: error)
        })
    }
    publicDatabase?.addOperation(queryOperation)
}
Run Code Online (Sandbox Code Playgroud)


Ala*_* T. 3

似乎有一些东西减慢了你的主线程,这导致了执行你的dispatch_async调用的捕获块的延迟。您的代码是否可能多次并行调用此记录获取函数?这将导致 NSData(contentsOfURL: asset.fileURL) 处理占用主线程并引入累积延迟。

无论如何,如果只是作为一个好的实践,使用 NSData 加载图像应该在后台执行,而不是在主线程上执行。