Parse getDataInBackgroundWithBlock not fetching in order

戏子无情 提交于 2019-12-08 10:06:37

问题


I am fetching a string, NSDate and a PFFile from my Parse class to populate the collection view cells

All the cells load with image, date, info correctly. The info and date are ordered correctly (by ascending date). But every now and then when I build some of the images will be in a different cell. Im really scratching my head with this. Im guessing it has something to do with how I'm calling mixPhoto.getDataInBackgroundWithBlock({

I did try and use dispatch_async(dispatch_get_main_queue())

Still no luck... Heres my code, anyone got any ideas?

@IBOutlet weak var collectionView1: UICollectionView!


var mixPhotoArray : Array<UIImage> = []
var mixInfoArray: Array <String> = []
var mixDateArray: Array <NSDate> = []

override func viewDidLoad() {
    super.viewDidLoad()
    collectionView1.delegate = self;
    collectionView1.dataSource = self;

    self.queryParseMethod()
    self.getImageData()

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Do any additional setup after loading the view.
}


func getImageData() {
    var query = PFQuery(className: "musicMixes")
    query.orderByAscending("date")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
    for object in objects {


    let mixPhoto = object["mixPhoto"] as PFFile

        mixPhoto.getDataInBackgroundWithBlock({
            (imageData: NSData!, error: NSError!) -> Void in
            if (error == nil) {
                dispatch_async(dispatch_get_main_queue()) {
                    let image = UIImage(data:imageData)
                    //image object implementation
                    self.mixPhotoArray.append(image!)
                    println(self.mixPhotoArray[0])
                    self.collectionView1.reloadData()

                }
            }
            else {
                println("error!!")
            }

        })//getDataInBackgroundWithBlock - end

        }



    }//for - end

}

    func queryParseMethod() {

    var query = PFQuery(className: "musicMixes")
    query.orderByAscending("date")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
        if error == nil {
            for object in objects {


    let mixPhoto = object["mixPhoto"] as PFFile




        let mixInfo = object["info"] as String
        let dateForText = object["date"] as NSDate


        //self.collectionView1.reloadData()

            self.mixDateArray.append(dateForText)
            self.mixInfoArray.append(mixInfo)
            self.collectionView1.reloadData()


                }//for - end
        }
        }
} // end of queryParseMethod


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()




        }



/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

// MARK: UICollectionViewDataSource

 func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    //#warning Incomplete method implementation -- Return the number of sections
    return 1
}


 func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    //#warning Incomplete method implementation -- Return the number of items in the section
     println("I have \(mixPhotoArray.count) Images")
    return mixInfoArray.count


}

  //func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let cell:StreamCollectionViewCell = collectionView1.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as StreamCollectionViewCell

   cell.mixImage.image = mixPhotoArray[indexPath.item]
    cell.infoLabel.text = mixInfoArray[indexPath.item]

    // NSDate array into cell
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
   cell.mixDateLabel.text = dateFormatter.stringFromDate(mixDateArray[indexPath.item])






     return cell
}

回答1:


Like Wain said, I believe the main issue is that since your images are downloading at different speeds, they're not necessarily being appended to your array in order. Instead of recommending that you use a dictionary though, here's what I would recommend to circumvent that problem while still using an array:

// Declare your mixPhotoArray such that it can store optionals
var mixPhotoArray : Array<UIImage?> = []

func getImageData() {

    var query = PFQuery(className: "musicMixes")
    query.orderByAscending("date")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
        // Initialize your array to contain all nil objects as
        // placeholders for your images
        self.mixPhotoArray = [UIImage?](count: objects.count, repeatedValue: nil)
        for i in 0...objects.count - 1 {

            let object: AnyObject = objects[i]
            let mixPhoto = object["mixPhoto"] as PFFile

            mixPhoto.getDataInBackgroundWithBlock({
                (imageData: NSData!, error: NSError!) -> Void in
                if (error == nil) {
                    dispatch_async(dispatch_get_main_queue()) {
                        let image = UIImage(data:imageData)
                        // Replace the image with its nil placeholder
                        // and do so using the loop's current index
                        self.mixPhotoArray[i] = image
                        println(self.mixPhotoArray[i])
                        self.collectionView1.reloadData()
                    }
                }
                else {
                    println("error!!")
                }

            })

        }

    }

}

Then within collectionView:cellForItemAtIndexPath, you can set the image conditionally so that it only appears once its ready:

if mixPhotoArray[indexPath.item] != nil {
    cell.mixImage.image = mixPhotoArray[indexPath.item]
}



回答2:


You are storing your data in 2 arrays, mixPhotoArray and mixInfoArray, but you can't guarantee that they will both be in the same order. Images are different sizes so they will download at different speeds. You also shouldn't really be trying to download more than 4 at once so your current scheme isn't great.

Instead, you should have an array of dictionaries or custom classes which hold all of the details and which, when each image is downloaded, is updated with that image.

Obviously this means that you need to know which one is associated with the image you've just downloaded so you need to capture this dictionary / instance in the block so you can update it.

You could do it in 2 arrays as you are, so long as you capture an index where the image should be an insert the image to the array in the correct place.



来源:https://stackoverflow.com/questions/28648188/parse-getdatainbackgroundwithblock-not-fetching-in-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!