慢速CloudKit表滚动 - 改变现有代码?

时间:2017-02-08 23:11:38

标签: 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
        {
            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!
}

2 个答案:

答案 0 :(得分:1)

设置代码的方式,无论何时滚动UITableView,您的程序都会将CKAsset转换为Data,然后将其转换为UIImage,这就是每个细胞!这是一个相当低效的过程,因此尝试创建一个名为Restaurant的NSObject,它具有image属性,当您浏览从CKQuery返回的所有记录时,将每条记录解析为一个新的{{ 1}}对象。要创建新的Restaurant,请转到文件 - &gt;新 - &gt;档案 - &gt;选择'Swift File'并添加如下内容:

NSObject

现在查询:

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

答案 1 :(得分:0)

您应该使用CKQueryOperation来实现UITableView的分页。

您必须将resultLimit属性设置为一个数字,该数字等于您在桌面上一次可见的单元格数量加3或4

设置recordFetchedBlock属性,您必须在其中实现将应用于一个CKRecord的代码

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

如果这个CKQueryCursor为nil,那么你已经到达了可用于查询的最后一条记录,但是如果它是一个非零值,那么你有更多的记录可以使用这个CKQueryCursor作为下一次获取的指示器来获取。

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

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