Reputation: 406
I have tried using other solutions with no luck. I need to save the data to an array of UIImages so when the cells are created it only has to assign the image from an array of already made images. The problem is that it is returning nil. Also I need to make sure that the images are in order.
/--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()
}
}
Upvotes: 0
Views: 84
Reputation: 131426
You actually have a rather complex problem. You have an outer async call, query.findObjectsInBackgroundWithBlock
, that passes an array of objects to it's completion closure, which is fine.
In that closure you run a loop, creating a whole bunch of async calls to load images. Those calls won't be done for an unpredictable amount of time.
Normally I'd say use a dispatch queue and a dispatch group so you could wait until all the tasks are done, but I assume you don't have the option of rewriting the imageFile.getDataInBackgroundWithBlock()
function.
What I would do is to add an instance variable, taskCount
, that tracks the number of tasks to be completed, run a closure on the main thread to decrement taskCount
each time an async download finishes, and tell the table view to reload once all the tasks are done:
//Put this outside the function and inside the definition of your class so it's
//an instance variable
var taskCount: Int
Then rewrite your call to query.findObjectsInBackgroundWithBlock
something like this:
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()
}
}
}
}
}
}
That code runs all of your calls to imageFile.getDataInBackgroundWithBlock
concurrently, but makes a call to the main thread to decrement the taskCount
in each one's completion closure. By decrementing the taskCount
on the main thread you avoid race conditions and only tell the table view to reload once all the images have been downloaded and the self.images
array is completely populated.
That should work. (I wrote this in the SO text editor, so it might need minor cleanup. The braces look like they aren't balanced correctly, but it should give you the idea.)
I changed the code above to preserve the order of the resulting objects in the list, and then edited it again to fix the for loop to use the enumerate()
function. (I forgot that bit.)
Upvotes: 1