0

I'm trying to reload the tableView when this loop is finished, but whenever i try to put the self.tableView.reloadData() outside the loop, the loop returns 0. I guess this is due to i'm getting the data in the background. What can i do in order to reload after the loop is completed.

func loadData() {
    var query = PFQuery(className: "Items")
    query.includeKey("user")
    query.getObjectInBackgroundWithId(itemId) {
        (itemObject: PFObject!, error: NSError!) -> Void in
        if (error == nil) {


            var userObject = itemObject.objectForKey("user") as PFObject


            let userImageFile = userObject.objectForKey("file") as PFFile
            userImageFile.getDataInBackgroundWithBlock {
                (imageData: NSData!, error: NSError!) -> Void in
                if error == nil {
                    let image = UIImage(data:imageData)






                    self.detailDic?.setObject(itemObject.objectForKey("title"), forKey: "title")
                    self.detailDic?.setObject(itemObject.objectForKey("description"), forKey: "desc")
                    self.detailDic?.setObject(itemObject.objectForKey("location"), forKey: "point")
                    self.detailDic?.setObject(userObject.objectForKey("name"), forKey: "name")
                    self.detailDic?.setObject(userObject.objectForKey("gender"), forKey: "gender")
                   self.detailDic?.setObject(image, forKey: "image")

                    var relation = itemObject.relationForKey("file") as PFRelation
                    var imageQuery = relation.query() as PFQuery
                    imageQuery.findObjectsInBackgroundWithBlock { (imageObj: [AnyObject]!, error1: NSError!) -> Void in
                        if error1 == nil {

                            var imageDic:NSMutableArray = NSMutableArray()

                            let group = dispatch_group_create()

                            for obj in imageObj {
                                var imageObject = obj as PFObject
                                var thumbnail = imageObject.objectForKey("file") as PFFile
                                // Important: enter the group *before* starting the background task.
                                dispatch_group_enter(group)
                                thumbnail.getDataInBackgroundWithBlock {
                                    (imageData: NSData!, error: NSError!) -> Void in
                                    if error == nil {
                                        let theImage = UIImage(data:imageData)
                                        theImage.CGImage
                                        self.imageArray!.addObject(theImage)
                                        dispatch_group_leave(group)
                                    }
                                }
                            }

                            dispatch_group_notify(group, dispatch_get_main_queue()) {
                                self.tableView?.reloadData()
                            }







                        }


                    }



                }

            }




        }


    }

}

2 Answers 2

2

Use a dispatch group. A dispatch group is basically a counter. You can increment and decrement it atomically, and you can ask to be notified when it is zero.

Each time you add a background task, “enter” the group (which increments its counter). When a background task finishes, “exit” the group (which decrements its counter). Use dispatch_group_notify to run a block when the counter is zero (meaning all background tasks have finished).

let group = dispatch_group_create()

for obj in imageObj {
    var imageObject = obj as PFObject
    var thumbnail = imageObject.objectForKey("file") as PFFile
    // Important: enter the group *before* starting the background task.
    dispatch_group_enter(group)
    thumbnail.getDataInBackgroundWithBlock {
        (imageData: NSData!, error: NSError!) -> Void in
        if error == nil {
            let theImage = UIImage(data:imageData)
            self.imageArray!.addObject(theImage)
            dispatch_group_leave(group)
        }
    }
}

dispatch_group_notify(group, dispatch_get_main_queue()) {
    self.tableView?.reloadData()
}

Note that if there are no elements in imageObj, or if all of the background tasks finish before dispatch_group_notify runs, dispatch_group_notify will run the block immediately (which is what you want).

Also, UIImage doesn't necessarily decode the image data when you create it. It can do so lazily. You may want to force it to decode the image data on the background thread. You can do that by asking for its CGImage:

        if error == nil {
            let theImage = UIImage(data:imageData)
            theImage.CGImage // force decoding immediately
            self.imageArray!.addObject(theImage)
            dispatch_group_leave(group)
        }
Sign up to request clarification or add additional context in comments.

2 Comments

on this line dispatch_group_notify i get cannot find member reloadData
Edit your question to include your new code. Show us the entire method, including the declaration.
0

You could also do:

for (index,obj) in enumerate(imageObj) {

    .......

    // reload after last loop 
    if(index == imageObj.count) {
        self.tableView?.reloadData()
    }

}

2 Comments

What if the last element of imageObj isn't the last to finish loading?
i guess your answer is still better. This is just an option if someone wants to do something after the last loop. (And this is what the Thread starter asked for) - so maybe a help if someone is looking for something like that

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.