如何按升序下载一行中的名称和图像

How to download name and images on one row in ascending order

我已经对此进行了研究,但似乎没有任何效果。我正在尝试构建一个食谱应用程序,但菜品图像和菜品名称(开胃菜)未按顺序下载。我该怎么做?

代码:

class Appetizers: UITableViewController {

    var valueToPass: String!
    var valuePassed: String!
    var appetizer = [String]()
    
    var images = [UIImage]()
    
    
    func refresh() {
        
        dispatch_async(dispatch_get_main_queue(), {
            
            self.tableView.reloadData()
            
        })
        
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Parse - class - column
        let query = PFQuery(className: "Appetizers")
        query.orderByAscending("appetizer")
        query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
        
            if error == nil {
                
                if let objects = objects {
                    
                    for object in objects {
                        
                        
                        
                        
                        let load = object.objectForKey("appetizer") as! String
                        self.appetizer.append(load)
                        
                        let imageFile = object["imageFiles"] as! PFFile
                        imageFile.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
                            
                            if error != nil {
                                
                                print(error)
                                
                            } else {
                                
                                if let data = imageData {
                                    
                                    self.images.append(UIImage(data: data)!)
                                    self.tableView.reloadData()
                                    
                                }
                                
                            }
                        })
                        
                        self.tableView.reloadData()
                        
                    }
                    
                }
                
            } else {
                
                print("Error: \(error!) \(error!.userInfo)")
                
            }
        }
        
        sleep(1)
        refresh()
    }
    
    
    override func viewWillAppear(animated: Bool) {
        
        self.tableView.reloadData()
    }
    

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return appetizer.count
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)

        cell.textLabel?.text = appetizer[indexPath.row]
        
        // add image to table
        if images.count > indexPath.row {
            
            cell.imageView?.image = images[indexPath.row]
            
        }

        return cell
    }
    
    
    // when user taps on cell ...
    
    func getCellLabel () {
        
        let indexPath = tableView.indexPathForSelectedRow!
        let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
        
        valueToPass = currentCell.textLabel!.text
        
    }
    
    
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        
        getCellLabel()
        self.performSegueWithIdentifier("0", sender: self)
        
    }


}

执行异步查询时,您无法保证它们完成的顺序。因此,两个独立数组的概念,一个是字符串数组,另一个是图像数组,总是有问题的。

例如,您可以将 images 替换为由开胃菜名称索引的字典,这样他们完成的顺序就无关紧要了。

var appetizer = [String]()
var images = [String: UIImage]()

因此,它可能看起来像:

override func viewDidLoad() {
    super.viewDidLoad()

    let query = PFQuery(className: "Appetizers")
    query.orderByAscending("appetizer")
    query.findObjectsInBackgroundWithBlock { objects, error in
        guard error == nil, let objects = objects else {
            print(error)
            return
        }

        for (index, object) in objects.enumerate() {
            let appetizerName = object.objectForKey("appetizer") as! String
            self.appetizer.append(appetizerName)

            let imageFile = object["imageFiles"] as! PFFile
            imageFile.getDataInBackgroundWithBlock { imageData, error in
                guard error == nil, let data = imageData else {
                    print(error)
                    return
                }

                // when the image comes in, asynchronously update only that one row

                self.images[appetizerName] = UIImage(data: data)
                self.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .Fade)
            }
        }

        // reload the table only once, after all of the `appetizer` entries are created (but likely before the images come in)

        self.tableView.reloadData()
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)

    let name = appetizer[indexPath.row]
    cell.textLabel?.text = name
    cell.imageView?.image = images[name]

    return cell
}

或者您可以将这两个单独的属性替换为一个自定义对象数组(例如,一个 Appetizer 对象同时具有 name 属性 和 image 属性).

但是无论你这样做,你都想确定你不是在处理两个单独的数组。


顺便说一句,但是如果您有很多行,加载所有图像的过程可能会出现问题。此代码使用 "eager" 图像加载(无论当前是否需要,都加载它们)。问题是图像是相对较大的资产(与字符串值相比),您可能 运行 遇到内存问题、网络带宽问题等

人们通常喜欢使用 "lazy" 加载(例如,让 cellForRowAtIndexPath 仅在需要时请求图像。例如,假设您有 200 行,其中只有 12 行一次可见点。你不应该请求 200 张图像,而应该只请求 12 张可见图像。如果你从 viewDidLoad 中取出图像检索,而是让 cellForRowAtIndexPath 一次请求一张,您将拥有更好的网络性能和更低要求的内存特性。

如果您要像代码当前那样以某种结构保存图像,至少要确保在收到内存警告通知后清除这些图像(并且,显然,优雅地处理重新 -根据需要以 JIT 方式请求它们)。

我发现了我的 table 没有 sleep() 无法加载的问题...... 我在街区外有 'self.tableView.reloadData()'。 Rob 帮了大忙 :)