我尝试使用其他解决方案没有运气。我需要将数据保存到UIImages数组中,因此在创建单元格时,它只需要从已制作的图像数组中分配图像即可。问题是它返回nil。另外,我需要确保图像井井有条。

/--UPDATING YOUR POSTS AFTER YOU POSTED--\\
func updatePosts(){
    if Reachability.isConnectedToNetwork() {
        self.images.removeAll(keepCapacity: true)

        let query = PFQuery(className: "Shoes")
        query.whereKey("createdBy", equalTo: PFUser.currentUser()!.username!)
        query.orderByDescending("createdAt")
        query.limit = 1000

        query.findObjectsInBackgroundWithBlock {
            (objects: [AnyObject]?, error: NSError?) -> Void in
            if error == nil {
                print("Successfully retrieved \(objects!.count) scores.")
                for object in objects! {

                    let imageFile = (object["imageFile"] as! PFFile)
                    imageFile.getDataInBackgroundWithBlock{
                        (imageData: NSData?, error: NSError?) -> Void in
                        if error == nil {
                            let image = UIImage(data: imageData!)
                            self.images.append(image!)
                        }
                    }

                    self.ids.append(object.objectId as String!)
                }
                dispatch_async(dispatch_get_main_queue(), {
                    self.collectionView.reloadData()
                })
            }
            else {
                print(error)
            }
        }


    } else {
        print("Internet connection not available")
        // This is Depreciated!!
        let alert = UIAlertView(title: "No Internet connection", message: "Please ensure you are connected to the Internet", delegate: nil, cancelButtonTitle: "OK")
        alert.show()
    }
}

最佳答案

您实际上有一个相当复杂的问题。您有一个外部异步调用query.findObjectsInBackgroundWithBlock,它将一个对象数组传递给它的完成闭包,这很好。

在该关闭中,您运行一个循环,创建了一堆异步调用来加载图像。这些呼叫不会在不可预测的时间内完成。

通常,我会说使用一个调度队列和一个调度组,以便您可以等待所有任务完成,但是我假设您没有重写imageFile.getDataInBackgroundWithBlock()函数的选项。

我要做的是添加一个实例变量taskCount,该变量跟踪要完成的任务数,在每次异步下载完成时在主线程上运行关闭命令以减小taskCount,并告诉表视图完成所有任务后重新加载:

//Put this outside the function and inside the definition of your class so it's
//an instance variable
var taskCount: Int


然后将呼叫改写为query.findObjectsInBackgroundWithBlock,如下所示:

query.findObjectsInBackgroundWithBlock
{
  (objects: [AnyObject]?, error: NSError?) -> Void in
  if error == nil
  {
    print("Successfully retrieved \(objects!.count) scores.")
    //Remember how many getDataInBackgroundWithBlock calls have to run
    //before we're done
    taskCount = objects.count
    //create an array of optionals and fill it with nils
    var tempImageArray = [UIImage?](count: objects.count, repeatedValue: nil)
    for (index, object) in objects!.enumerate()
    {
      let imageFile = (object["imageFile"] as! PFFile)
      imageFile.getDataInBackgroundWithBlock
      {
        (imageData: NSData?, error: NSError?) -> Void in
        if error == nil
        {
          let image = UIImage(data: imageData!)
          tempImageArray[index = image;

          //We're done with this one, so tell the main thread
          //to decrement the taskCount
          dispatch_async(dispatch_get_main_queue())
          {
            taskCount--
            if taskCount == 0
            {
              self.images = tempImages.map({$0!})
              self.collectionView.reloadData()
            }
          }
        }
      }
  }
}


该代码同时运行您对imageFile.getDataInBackgroundWithBlock的所有调用,但是对主线程进行调用以在每个人的完成闭合中减小taskCount。通过减少主线程上的taskCount可以避免竞争情况,并且仅在下载完所有映像并且完全填充self.images数组后,才告诉表视图重新加载。

那应该工作。 (我在SO文本编辑器中编写了此代码,因此可能需要进行少量清理。大括号看起来好像它们的平衡不正确,但是应该可以给您带来灵感。)

编辑:

我更改了上面的代码以保留列表中结果对象的顺序,然后再次对其进行编辑以修复for循环以使用enumerate()函数。 (我忘了那一点。)

09-09 23:50