我在我的应用中使用CloudKit作为远程持久保存数据的方法。我的一个记录有一个CKAsset属性,用于保存图像。当我提取记录时,我意识到它花了很多时间来完成查询。经过多次测试,我得出结论,当您查询记录时,CloutKit会使用记录对象下载整个Asset文件。因此,当您从记录对象获取资产并请求它的fileURL时,它会为您提供本地文件路径URL而不是HTTP类型的URL。这对我来说是个问题,因为你必须让用户等待这么多时间才能在查询结束之前下载整个记录(及其相关图像)。来自Parse背景,Parse用于为您提供HTTP URL,并且查询足够快以在加载图像异步时加载具有对象的UI。我的问题是,我怎样才能实现Parse的作用?我需要限制查询下载Assets数据并获取一个链接以异步加载图像。
答案 0 :(得分:5)
您可以使用CloudKit JavaScript访问资产的网址。这是一个例子;
(已使用Alamofire和SwiftyJSON)
func testRecordRequest() -> Request {
let urlString = "https://api.apple-cloudkit.com/database/1/" + Constants.container + "/development/public/records/query?ckAPIToken=" + Constants.cloudKitAPIToken
let query = ["recordType": "TestRecord"]
return Alamofire.request(.POST, urlString, parameters: ["query": query], encoding: .JSON, headers: nil)
}
JSON响应包含" downloadURL"对于资产。
"downloadURL": "https://cvws.icloud-content.com/B/.../${f}?o=AmVtU..."
" $ {F}"看起来像一个变量,所以把它改成你喜欢的任何东西。
let downloadURLString = json["fields"][FieldNames.image]["value"]["downloadURL"].stringValue
let recordName = json["recordName"].stringValue
let fileName = recordName + ".jpg"
let imageURLString = downloadURLString.stringByReplacingOccurrencesOfString("${f}", withString: fileName)
现在我们可以使用这个urlString创建一个NSURL,并将它用于任何图像和缓存解决方案,如Kingfisher,HanekeSwift等。 (您可能还想保存图像类型png / jpg)
答案 1 :(得分:3)
对同一记录进行两次单独调用。第一个调用应该获取所需的所有非资产字段,然后第二个请求应该获取所需的资产。
类似的东西:
let dataQueryOperation = CKQueryOperation(query: CKQuery(predicate: myPredicate)
dataQueryOperation.desiredKeys = ["name", "age"] // etc
database.addOperation(dataQueryOperation)
let imageQueryOperation = CKQueryOperation(query: CKQuery(predicate: myPredicate)
imageQueryOperation.desiredKeys = ["images"]
database.addOperation(imageQueryOperation)
如果需要,将其重构为一个方法,这样您就可以轻松地为每个包含资产的字段创建一个新的CKQueryOperation。
快乐狩猎。
答案 2 :(得分:0)
像其他人一样说你无法获得CKAsset的url(web)。所以你最好的选择是 1.使用每个UIImageView具有进度的获取操作。我已经构建了一个向用户显示进度的自定义。不包括缓存,但您可以创建一个类并采用NSCoding并将整个记录保存到缓存目录。在这里,您可以看到我已完成的提取,将资产发送回我调用的地方,将其与我的其他数据相结合。
// only get the asset in this fetch. we have everything else
让operation = CKFetchRecordsOperation(recordIDs:[myRecordID])
operation.desiredKeys = ["GameTurnImage"]
operation.perRecordProgressBlock = {
record,progress in
dispatch_async(dispatch_get_main_queue(), {
self.progressIndicatorView.progress = CGFloat(progress)
})
}
operation.perRecordCompletionBlock = {
record,recordID,error in
if let _ = record{
let asset = record!.valueForKey("GameTurnImage") as? CKAsset
if let _ = asset{
let url = asset!.fileURL
let imageData = NSData(contentsOfFile: url.path!)!
dispatch_async(dispatch_get_main_queue(), {
self.image = UIImage(data: imageData)
self.progressIndicatorView.reveal()
})
completion(asset!)
}
}
}
CKContainer.defaultContainer().publicCloudDatabase.addOperation(operation)
另一种选择是将图像存储在AWS服务器或类似的东西上,然后您可以使用SDWebImage之类的东西来执行所有缓存或繁重工作,并将CKRecord中的字符串保存到图像中。
我已经向几个人询问了一个用于公开网址的CKAsset功能。我不知道关于CloudKit的JS Api,但可能有办法用这个来做,但我会让其他人对此做出反应。
答案 3 :(得分:0)
这是我的方法。
假设我的记录类型是:图书
BookID(自动ID或您的唯一ID)
BookName字符串
BookImage CKAsset
BookURL字符串
如果我使用我存储在BookURL中的CKAssest: “资产:\ BookID.png” 如果我使用外部服务器存储图像,则在BookURL中使用普通URL “ http://myexternalServer \ images \ BookID.png”
查询:
带有期望的键,我查询所有没有BookImage(CKAsset)字段的字段。
如果BookURL为空,则该书没有图像。
如果BookURL以“ Asset:\”开头,我从cloudkit中查询BookImage
如果BookURL是正常URL,我将从外部服务器(NSUrlSession)下载图像
这样,只要有时间,我就可以更改并决定如何在cloudkit(CKAssets)或外部服务器(http下载)上存储图像