Swift CloudKit表滚动速度慢-更改现有代码?

Swift CloudKit表滚动速度慢-更改现有代码?,swift,image,uitableview,scroll,cloudkit,Swift,Image,Uitableview,Scroll,Cloudkit,下面我有我现有的查询下载和表格行代码的单元格 publicDB.perform(query, inZoneWith: nil) { (results, error) -> Void in if (error != nil) { self.present(alert, animated: true, completion: nil) } else {

下面我有我现有的查询下载和表格行代码的单元格

 publicDB.perform(query, inZoneWith: nil)
    {
        (results, error) -> Void in
        if (error != nil)
        {
            self.present(alert, animated: true, completion: nil)
        }
        else
        {
            for result in results!
            {
                self.restaurantArray.append(result)
            }
            OperationQueue.main.addOperation( { () -> Void in
                self.tableView.reloadData()
            }) } }}
downloadRestaurants()
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantcell") as? RestaurantTableCell
    let restaurant: CKRecord = restaurantArray[indexPath.row]
    cell?.name?.text = restaurant.value(forKey: "Name") as? String
    let asset = restaurant.value(forKey: "Picture") as! CKAsset 
    let data = try! Data(contentsOf: asset.fileURL)
   _ = UIImage(data: data)
    cell?.picture?.image = UIImage(data: data)
   return cell!
}
当我运行这段代码时,应用程序仍能正常运行,但在大约10个表格单元格中滚动时,会出现令人难以置信的波动。我不确定是什么原因造成的-所有记录,每个都包含一个图像,都是在top函数的查询下载部分下载的。然而,我缺少的一个问题或概念在运行时始终存在。我错过了什么?延迟加载?隐藏物还有别的吗?目前还不确定,所以任何帮助都会非常有用

更新1:

我更新了我的代码,非常感谢你来到皮尔斯。我不得不从他的回答中稍微更新我的代码,以维护一个ckrecord数组,通过-restaurantArray切换到另一个控制器,同时也为NSObject类-tablerestaurantarray创建一个新数组,以显示在当前表控制器中

   var restaurantArray: Array<CKRecord> = []
    var tablerestaurantarray: [Restaurant] = []

for result in results!
            {
                let tablerestaurant = Restaurant()

                if let name = result.value(forKey: "Name") as! String? {
                    tablerestaurant.name = name
                }
                // Do same for image
                if let imageAsset = result.object(forKey: "Picture") as! CKAsset? {

                    if let data = try? Data(contentsOf: imageAsset.fileURL) {
                        tablerestaurant.image =  UIImage(data: data)
                    }
                }
                self.tablerestaurantarray.append(tablerestaurant)

                self.restaurantArray.append(result)
            }
            OperationQueue.main.addOperation( { () -> Void in
                self.tableView.reloadData()     
            })
        }
    }
}
downloadRestaurants() 
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return restaurantArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantcell") as? RestaurantTableCell

    let restaurant: Restaurant = tablerestaurantarray[indexPath.row]
    cell?.name?.text = restaurant.name

    cell?.picture?.image = restaurant.image
    return cell!
}

代码的设置方式,无论何时在UITableView中滚动,您的程序都在将CKAsset转换为数据,然后将其转换为UIImage,这在每个单元格中!这是一个相当低效的过程,因此请尝试创建一个名为Restaurant之类的对象,该对象具有image属性,当您查看从CKQuery返回的所有记录时,将每个记录解析为一个新的Restaurant对象。要创建新的NSObject,请转到文件->新建->文件->选择“Swift文件”,并添加如下内容:

import UIKit

class Restaurant: NSObject {

    // Create a UIImage property
    var image: UIImage?

    // Add any other properties, i.e. name, address, etc.
    var name: String = ""
}
现在请回答您的问题:

// Create an empty array of Restaurant objects
var restaurantArray: [Restaurant] = []

publicDB.perform(query, inZoneWith: nil) { (results, error) -> Void in
    if (error != nil) {
        self.present(alert, animated: true, completion: nil)
    } else {
        for result in results! {

            // Create a new instance of Restaurant
            let restaurant = Restaurant()

            // Use optional binding to check if value exists
            if let name = result.value(forKey: "Name") as! String? {
                restaurant.name = name
            }
            // Do same for image
            if let imageAsset = result.object(forKey: "Picture") as! CKAsset? {

                if let data = try? Data(contentsOf: imageAsset.fileURL) {
                    restaurant.image =  UIImage(data: data)
                }
            }

            // Append the new Restaurant to the Restaurants array (which is now an array of Restaurant objects, NOT CKRecords)
            self.restaurantArray.append(restaurant)
        }
        OperationQueue.main.addOperation( { () -> Void in
            self.tableView.reloadData()
        }) 
    } 
}
现在,您的单元设置更简单:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "restaurantcell") as? RestaurantTableCell

    let restaurant: Restaurant = restaurantArray[indexPath.row]
    cell?.name?.text = restaurant.name

    cell?.picture?.image = restaurant.image
    return cell!
}
您应该使用以实现UITableView的分页

您必须将属性设置为一个数字,该数字等于表上一次可访问的单元格数量加上3或4

在必须实现将应用于一条CKRecord的代码的位置设置属性

设置属性。这是分页代码中最重要的部分,因为此闭包接收可选的CKQueryCursor参数

如果此CKQueryCursor为nil,则您已到达可供查询的最后一条记录,但如果它是非nil值,则您将有更多记录要使用此CKQueryCursor作为下一次提取的指示符进行提取

当用户在TableView上滚动并到达最后一个元素时,您应该使用CKQueryCursor执行另一次获取


其他性能建议是,应在单独的执行队列中处理CKAssets。

每次在tableView中滚动时,应用程序都必须将CKAsset转换为数据,然后将其转换为UIImage。我建议创建一种称为Restaurant之类的NSObject,然后在执行查询时,从CKRecords数组中获取每条记录,并将其解析为具有UIImage属性的Restaurant对象,然后使用这些对象中的图像填充单元格。这样,它只需要抓取一个UIImage,而不是每次都转换它。皮尔斯,你能提供一个代码示例吗?在我的项目中,我以前从未使用过NSObjects,所以我在这方面有点落后。请看下面我的答案。皮尔斯,我非常感谢你的答案。请看一下我的更新代码。问题是。。。虽然代码按预期工作,但在最初的几个滚动过程中有轻微的减速。然而,一旦我坐到桌子的底部,一切都像我希望的那样快。你知道吗?如果你第一次滚动浏览图像时图像还没有被缓存,那么当你把它放到底部时,每个图像都会被缓存,这可能是一个非常典型的问题。查看此答案以查看解决方案-注意:答案在Objective-C中,但在最顶端有一个链接指向GitHub gist,该GitHub gist在Swift中具有相同的解决方案。祝你好运