Cloudkit 获取很慢
Cloudkit Fetch very slow
运行 下面的代码从 Cloudkit 获取数据,目前填充 tableView 需要很长时间,具体取决于有多少结果,但如果超过 15 个结果需要 10 秒以上。他们有什么方法可以加快速度吗?
这是我的获取函数:
func loadData() {
venues = [CKRecord]()
let location = locationManager.location
let radius = CLLocationDistance(500)
let sort = CKLocationSortDescriptor(key: "Location", relativeLocation: location!)
let predicate = NSPredicate(format: "distanceToLocation:fromLocation:(%K,%@) < %f", "Location", location!, radius)
let publicData = CKContainer.defaultContainer().publicCloudDatabase
let query = CKQuery(recordType: "Venues", predicate: predicate )
query.sortDescriptors = [sort]
publicData.performQuery(query, inZoneWithID: nil) { (results:[CKRecord]?, error:NSError?) in
if let venues = results {
self.venues = venues
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
self.refreshControl.endRefreshing()
self.tableView.hidden = false
})
}
}
}
这是我的 tableView 函数:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! NearMe2ViewCell
if venues.count == 0 {
return cell
}
let venue = venues[indexPath.row]
print(indexPath.row)
let venueLocation = venue["Location"] as? CLLocation
let venueTitle = (venue["Name"] as! String)
let venueImages = venue["VenuePhoto"] as! CKAsset
let userLocation = locationManager.location
let distanceBetween: CLLocationDistance = (venueLocation!.distanceFromLocation(userLocation!))
self.venueDistance = String(format: "%.f", distanceBetween)
cell.venueDistance?.text = venueDistance
cell.venueName.text = venueTitle
cell.venueImage?.image = UIImage(contentsOfFile: venueImages.fileURL.path!)
return cell
}
您应该首先搜索记录键,因此 fetchOperation 将包含此指令。
fetchOperation.desiredKeys = ["record.recordID.recordName"]
那应该会更快。将您的 returned 键分解成您可以在屏幕上显示的大小,然后只获取它们。显示它们后,在后台线程中获取下一批,当您在后台获取下一批时,等等等等。
也许应该补充一点,如果可能的话,获取资产也应该在一个单独的线程上完成,通过反复重新加载 table 来更新 table。
这是搜索和 return 键的方法。
func zap(theUUID:String) {
var recordID2Zap: String!
let predicate = NSPredicate(format: "(theUUID = %@)",theUUID)
let query = CKQuery(recordType: "Blah", predicate: predicate)
let searchOperation = CKQueryOperation(query: query)
searchOperation.desiredKeys = ["record.recordID.recordName"]
searchOperation.recordFetchedBlock = { (record) in
recordID2Zap = record.recordID.recordName
}
if error != nil {
print("ting, busted",error!.localizedDescription)
} else {
print("ok zapping")
if recordID2Zap != nil {
self.privateDB.delete(withRecordID: CKRecordID(recordName: recordID2Zap), completionHandler: {recordID, error in
NSLog("OK or \(error)")
})
}
}
}
searchOperation.qualityOfService = .background
privateDB.add(searchOperation)
theApp.isNetworkActivityIndicatorVisible = true
}
}
至于您的 table 视图和图像...使用您的 icloud 代码中的完成功能向 table 视图发送通知。
database.fetchRecordWithID(CKRecordID(recordName: recordId), completionHandler: {record, error in
let directDict = ["blah": "whatever"] as [String : String]
NotificationCenter.default.post(name: Notification.Name("blahDownloaded"), object: nil, userInfo: directDict)
}
然后在 VC 中注册所述通知。
NotificationCenter.default.addObserver(self, selector: #selector(blahDownloaded), name: Notification.Name("blahDownloaded"), object: nil)
func blahDownloaded(notification: NSNotification) {
if let userInfo = notification.userInfo as NSDictionary? as? [String: Any] {
//update you cell
//reload your table
}
这一切都有意义吗?
您的操作 qualityOfService
默认为 .utility
。
documentation for CKOperation
中有一条重要说明指出:
CKOperation objects have a default quality of service level of NSQualityOfServiceUtility (see qualityOfService). Operations at this level are considered discretionary, and are scheduled by the system for an optimal time based on battery level and other factors.
因为 CKOperation
继承自 NSOperation
您可以在用户等待请求完成时配置 qualityOfService
属性。这是一些基于您上面的示例代码:
let queryOperation = CKQueryOperation(query: query)
queryOperation.recordFetchedBlock = ...
queryOperation.queryCompletionBlock = ...
queryOperation.qualityOfService = .userInteractive
publicData.add(queryOperation)
请注意,此示例显式创建了一个 CKQueryOperation
而不是使用方便的 API,因为它使您可以灵活地在将操作排队发送到服务器之前完全配置您的操作。
在这种情况下,您可以将 qualityOfService
设置为 .userInteractive
,因为您的用户正在积极等待请求完成,然后才能进一步使用您的应用。在 https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html
了解有关可能值的更多信息
运行 下面的代码从 Cloudkit 获取数据,目前填充 tableView 需要很长时间,具体取决于有多少结果,但如果超过 15 个结果需要 10 秒以上。他们有什么方法可以加快速度吗?
这是我的获取函数:
func loadData() {
venues = [CKRecord]()
let location = locationManager.location
let radius = CLLocationDistance(500)
let sort = CKLocationSortDescriptor(key: "Location", relativeLocation: location!)
let predicate = NSPredicate(format: "distanceToLocation:fromLocation:(%K,%@) < %f", "Location", location!, radius)
let publicData = CKContainer.defaultContainer().publicCloudDatabase
let query = CKQuery(recordType: "Venues", predicate: predicate )
query.sortDescriptors = [sort]
publicData.performQuery(query, inZoneWithID: nil) { (results:[CKRecord]?, error:NSError?) in
if let venues = results {
self.venues = venues
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
self.refreshControl.endRefreshing()
self.tableView.hidden = false
})
}
}
}
这是我的 tableView 函数:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! NearMe2ViewCell
if venues.count == 0 {
return cell
}
let venue = venues[indexPath.row]
print(indexPath.row)
let venueLocation = venue["Location"] as? CLLocation
let venueTitle = (venue["Name"] as! String)
let venueImages = venue["VenuePhoto"] as! CKAsset
let userLocation = locationManager.location
let distanceBetween: CLLocationDistance = (venueLocation!.distanceFromLocation(userLocation!))
self.venueDistance = String(format: "%.f", distanceBetween)
cell.venueDistance?.text = venueDistance
cell.venueName.text = venueTitle
cell.venueImage?.image = UIImage(contentsOfFile: venueImages.fileURL.path!)
return cell
}
您应该首先搜索记录键,因此 fetchOperation 将包含此指令。
fetchOperation.desiredKeys = ["record.recordID.recordName"]
那应该会更快。将您的 returned 键分解成您可以在屏幕上显示的大小,然后只获取它们。显示它们后,在后台线程中获取下一批,当您在后台获取下一批时,等等等等。
也许应该补充一点,如果可能的话,获取资产也应该在一个单独的线程上完成,通过反复重新加载 table 来更新 table。
这是搜索和 return 键的方法。
func zap(theUUID:String) {
var recordID2Zap: String!
let predicate = NSPredicate(format: "(theUUID = %@)",theUUID)
let query = CKQuery(recordType: "Blah", predicate: predicate)
let searchOperation = CKQueryOperation(query: query)
searchOperation.desiredKeys = ["record.recordID.recordName"]
searchOperation.recordFetchedBlock = { (record) in
recordID2Zap = record.recordID.recordName
}
if error != nil {
print("ting, busted",error!.localizedDescription)
} else {
print("ok zapping")
if recordID2Zap != nil {
self.privateDB.delete(withRecordID: CKRecordID(recordName: recordID2Zap), completionHandler: {recordID, error in
NSLog("OK or \(error)")
})
}
}
}
searchOperation.qualityOfService = .background
privateDB.add(searchOperation)
theApp.isNetworkActivityIndicatorVisible = true
}
}
至于您的 table 视图和图像...使用您的 icloud 代码中的完成功能向 table 视图发送通知。
database.fetchRecordWithID(CKRecordID(recordName: recordId), completionHandler: {record, error in
let directDict = ["blah": "whatever"] as [String : String]
NotificationCenter.default.post(name: Notification.Name("blahDownloaded"), object: nil, userInfo: directDict)
}
然后在 VC 中注册所述通知。
NotificationCenter.default.addObserver(self, selector: #selector(blahDownloaded), name: Notification.Name("blahDownloaded"), object: nil)
func blahDownloaded(notification: NSNotification) {
if let userInfo = notification.userInfo as NSDictionary? as? [String: Any] {
//update you cell
//reload your table
}
这一切都有意义吗?
您的操作 qualityOfService
默认为 .utility
。
documentation for CKOperation
中有一条重要说明指出:
CKOperation objects have a default quality of service level of NSQualityOfServiceUtility (see qualityOfService). Operations at this level are considered discretionary, and are scheduled by the system for an optimal time based on battery level and other factors.
因为 CKOperation
继承自 NSOperation
您可以在用户等待请求完成时配置 qualityOfService
属性。这是一些基于您上面的示例代码:
let queryOperation = CKQueryOperation(query: query)
queryOperation.recordFetchedBlock = ...
queryOperation.queryCompletionBlock = ...
queryOperation.qualityOfService = .userInteractive
publicData.add(queryOperation)
请注意,此示例显式创建了一个 CKQueryOperation
而不是使用方便的 API,因为它使您可以灵活地在将操作排队发送到服务器之前完全配置您的操作。
在这种情况下,您可以将 qualityOfService
设置为 .userInteractive
,因为您的用户正在积极等待请求完成,然后才能进一步使用您的应用。在 https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html