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...