The main thread locked when fetching images from parse with semaphore

443 views Asked by At

I have a very big problem. I use Parse cloud system. When i fetch images with using "dispatch_semaphore" from parse, the main thread is locked. However, i think, i don't use main thread when fetching images. Normally, the task should be executed order by section A,B,C then D but app locked in section B.

Thanks.

    let semaphore1:dispatch_semaphore_t = dispatch_semaphore_create(0)
    let semaphore2:dispatch_semaphore_t = dispatch_semaphore_create(0)

    let userquery = PFQuery(className: "_User")

    userquery.findObjectsInBackground().continueWithSuccessBlock { (task) -> AnyObject? in

        let results = task.result as! NSArray

        for objectarray  in results
        {
            let object = objectarray as! PFObject
            let username = object["username"] as! String
            let userpictureThumbnail = object["userPhotoThumbnail"] as! PFFile
            userpictureThumbnail.getDataInBackground().continueWithSuccessBlock({ (task2) -> AnyObject? in

                let result = task2.result as! NSData
                let image = UIImage(data: result)
                let imageThumbnail = image

                // Section C-) Below codes must be executed but main thread is locked by Section B.
                Model.sharedInstance.friendsPictureModel.addItem(username,FriendImageThumbnail:imageThumbnail!)

                dispatch_semaphore_signal(semaphore2)
                return nil

            })

            // Section B-) Second, enter the  below code . And lock main thread then app freezed.
            dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER)
        }
        dispatch_semaphore_signal(semaphore1)
        return nil 
    }

    // Section A-) When the block("userquery.findObjectsInBackground().continueWithSuccessBlock") is executed, enter the  below code firstly.
    dispatch_semaphore_wait(semaphore1, DISPATCH_TIME_FOREVER)

    // Section D-) Below codes must be executed in the last.
    self.collectionview.reloadData()
1

There are 1 answers

0
Michael On

You should not be using semaphores here. Your section A is (presumably) running on the main thread, and the wait will cause it to block until the semaphore is signalled.

You could remove all the semaphore code and just dispatch self.collectionview.reloadData() onto the main thread in where semaphore2 is currently being signalled. However, you also have a problem that addItem is being called in the background, and it's probably not thread safe.

On the assumption that your example is a simplification of your specific problem, you probably have some separation between the viewController and userquery (let's call it findTheObjects. So at the moment you would have something like:

myObjectFinder.findTheObjects()

In this case, you should pass in your own completion block, along the lines of:

myObjectFinder.findTheObjects(completion: {
    (username, imageThumbnail?) -> Void in
    dispatch_async(dispatch_get_main_queue(), {
        // do something with the results like...
        Model.sharedInstance.friendsPictureModel.addItem(username,FriendImageThumbnail:theResults.imageThumbnail!)
        self.collectionview.reloadData()
    })
}

This completion block would then be called from your Section C.