Loop within block appending to array in the wrong order - Swift 2.0

痴心易碎 提交于 2019-12-12 14:01:18

问题


I have an array of PFFiles downloaded from Parse, and I am trying to convert them in to an array of NSData (imageDataArray) in order to save them to Core Data. The only problem I seem to be having now is that the elements of imageDataArray are being added in the wrong order, which means the wrong image is found when I search through Core Data.

I found this question (Stack Overflow Question) which seems to explain the reason for the problem as being that the block is completing the tasks at different times, therefore the order of the array is based on whichever is finished first. They then suggest using Grand Central Dispatch, but it is all in Obj C and, as a newbie to coding, I am struggling to convert it to Swift for my project.

Could you please explain to me how I would use GCD (or any other method) to create the imageDataArray in the same order as the original PFFile array?

    override func viewDidLoad() {
    super.viewDidLoad()


    let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

    let context: NSManagedObjectContext = appDel.managedObjectContext


   let dealsQuery = PFQuery(className: ("Deals"))
    dealsQuery.orderByAscending("TrailId")

    dealsQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
        if let objects = objects {

            self.trailID.removeAll(keepCapacity: true)
            self.trailStep.removeAll(keepCapacity: true)
            self.dealNumber.removeAll(keepCapacity: true)
            self.imageFile.removeAll(keepCapacity: true)

            for object in objects {

                self.trailID.append(object["TrailID"] as! Int)
                self.trailStep.append(object["TrailStep"] as! Int)
                self.dealNumber.append(object["dealNumber"] as! Int)
                self.imageFile.append(object["dealImage"] as! PFFile!)

            }

        }


            var counter = 0

            for file in self.imageFile {

            let dealImage = file

            dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in

                if error == nil {

                    weak var aBlockSelf = self

                    let image = UIImage(data: imageData!)
                    aBlockSelf!.imageDataArray.append(imageData!)
                    self.imagesArray.append(image!)

                    if counter == self.trailStep.count - 1{

                        print(self.trailID.count)
                        print(self.trailStep.count)
                        print(self.dealNumber.count)
                        print(self.imageDataArray.count)

                        print(self.trailStep[0])
                        print(self.dealNumber[0])
                        let image = UIImage(data: self.imageDataArray[0])
                        self.imageView.image = image

                    } else {counter++}
                }

            })

Sorry for posting all of my code here. I guess the issue is at the bottom, but as a beginner I thought I might have made a mistake somewhere else so thought I would be best posting it all.

Thanks a lot for your help.


Update 1

I have tried adding a prefilled array (imageArray) and trying to put the data in to that, but it still comes out random when searching for trailStep and dealNumber. What am I missing? Thanks

 var i = 0

            var imageArray = [NSData!](count: self.trailStep.count, repeatedValue: nil)

            for file in self.imageFile {

            let dealImage = file

            dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in

                if error == nil {

                    //weak var aBlockSelf = self

                    let image = UIImage(data: imageData!)
                    imageArray[i] = imageData!

                    if i == self.trailStep.count - 1{

                        print(self.trailID.count)
                        print(self.trailStep.count)
                        print(self.dealNumber.count)
                        print(self.imageDataArray.count)

                        print(self.trailStep[3])
                        print(self.dealNumber[3])
                        let image = UIImage(data: imageArray[3])
                        self.imageView.image = image

                    } else {i++}
                }

            })

Update 2

I have been researching and having a play around with GCD and serial dispatches, and here is where I am at the moment. I think I am taking a far too simplistic view of GCD but can't quite get my head around how it works and how it can get my block to add to imageDataArray in the right order.

var counter = 0

        var imageArray = [NSData!](count: self.trailStep.count, repeatedValue: nil)

        weak var aBlockSelf = self

        var serialQueue = dispatch_queue_create("serial", nil)

        for file in self.imageFile {

            let dealImage = file

            var imageDataArray = [NSData!](count: self.imageFile.count, repeatedValue: nil)

            dispatch_async(serialQueue, { () -> Void in

            dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in



                    if error == nil {

                        let imageIndex = self.imageFile.indexOf(file)
                        let image = UIImage(data: imageData!)
                        imageDataArray.insert(imageData!, atIndex: imageIndex!)

                        if counter == self.trailStep.count - 1{

                            print(self.trailID.count)
                            print(self.trailStep.count)
                            print(self.dealNumber.count)
                            print(imageDataArray.count)

                            print(self.trailStep[0])
                            print(self.dealNumber[0])
                            let image = UIImage(data: imageDataArray[4])
                            self.imageView.image = image

                        } else {counter++}

                        return
                    }

                })

This code is returning an error of "unexpectedly found nil while unwrapping an Optional value" on the line " let image = UIImage(data: imageDataArray[4])". This is the same error that I was getting before I tried to implement the GCD...


回答1:


This should be fairly simple. Although GCD dispatch group would be ideal choice, you can solutionize this by keeping a counter of for loop.

In your completion block, deduce the index of the object you are currently inside the for loop using the parent array. In your final image array, add object at the index captured by this index.

EDIT: Post OP question - here is a quick sneak peek of how I would like it to be:

weak var aBlockSelf = self

for file in self.imageFile {

    let dealImage = file

    dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in

        if error == nil {
            let imageIndex = self.imageFile.indexOf(file)
            let image = UIImage(data: imageData!)
            aBlockSelf.imageDataArray.insert(imageData!, atIndex: imageIndex)
            aBlockSelf.imagesArray.insert(image!, atIndex: imageIndex)

As a side not, do not declare self weak reference in the for loop. You should declare it outside.




回答2:


You don't need to use GCD for this; you just need an array (or map, if you want to associate each image with its filename) to stick each image in when it's retrieved. In other words, if you have files "f1", "f2", "f3", and "f4", in that order, create an array to hold the retrieved images, and insert them at whatever index corresponds to their filename's index in the list of filenames.



来源:https://stackoverflow.com/questions/33429044/loop-within-block-appending-to-array-in-the-wrong-order-swift-2-0

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