简体   繁体   English

Cloudkit提取非常慢

[英]Cloudkit Fetch very slow

Running the below code to fetch data from Cloudkit, at the moment it is taking a long to populate a tableView, depending on how many results there are, but if there are over 15 results it takes 10 seconds plus. 运行以下代码从Cloudkit中获取数据,目前,填充tableView花费的时间很长,具体取决于结果的数量,但是如果结果超过15个,则需要10秒钟以上的时间。 Are they any ways I can speed this up? 他们有什么办法可以加快速度吗?

This is my fetch func: 这是我的提取函数:

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
                })
            }
        }
    }

This is my tableView func: 这是我的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


    }

You should search for the record keys first, so a fetchOperation would include this directive. 您应该首先搜索记录键,因此fetchOperation将包含此指令。

fetchOperation.desiredKeys = ["record.recordID.recordName"]

That should be faster. 那应该更快。 Break your returned keys into the size you can display on the screen and go get them only. 将返回的键拆分为可以在屏幕上显示的大小,然后仅获取它们。 After you display them, go get the next batch in background thread, when you got that the next batch on background etc etc etc. 显示它们后,在后台线程中获取下一批,在后台等时获得下一批,等等。

Should add perhaps, that fetching the asset should be done on a separate thread too if possible, updating the table as you pull in the assets by reloading the table repeatedly. 应该补充一点,如果可能的话,资产的获取也应该在单独的线程上完成,在您通过重复加载表来获取资产时更新表。

Here is method to search and return keys. 这是搜索和返回键的方法。

 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
}

}

As for your tableview, and images... use the completion in your icloud code to send a notification to the table view. 至于您的表格视图和图像...在icloud代码中使用补全将通知发送到表格视图。

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)
}

And in the VC you register said notification. 然后在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
}

Does that all make sense? 这一切有意义吗?

Your operation's qualityOfService is defaulting to .utility . 你操作的qualityOfService被默认为.utility

There is an important note in the documentation for CKOperation that states: CKOperation文档中有一个重要说明,指出:

CKOperation objects have a default quality of service level of NSQualityOfServiceUtility (see qualityOfService). CKOperation对象的默认服务质量级别为NSQualityOfServiceUtility(请参阅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. 此级别的操作被认为是可任意选择的,并且由系统根据电池电量和其他因素在最佳时间安排。

Because CKOperation inherits from NSOperation you can configure the qualityOfService property when your user is waiting on a request to finish. 由于CKOperation从继承NSOperation可以配置qualityOfService当你的用户正在等待完成一个请求属性。 Here is some example code based off of yours above: 这是基于上述代码的一些示例代码:

let queryOperation = CKQueryOperation(query: query)
queryOperation.recordFetchedBlock = ...
queryOperation.queryCompletionBlock = ...

queryOperation.qualityOfService = .userInteractive

publicData.add(queryOperation)

Notice that this example explicitly creates a CKQueryOperation instead of using the convenience API because it then gives you the flexibility to fully configure your operations before you enqueue them to be sent to the server. 请注意,此示例显式创建了CKQueryOperation而不是使用便捷API,因为它使您可以灵活地在将操作排队发送到服务器之前完全配置您的操作。

In this case you can set the qualityOfService to .userInteractive because your user is actively waiting on the request to finish before they can use your app any further. 在这种情况下,您可以设置qualityOfService.userInteractive因为你的用户正在积极等待的请求的完成它们可以在任何进一步的使用你的应用程序之前。 Learn more about the possible values at https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html上了解有关可能值的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM