riverhawk riverhawk - 4 months ago 9
iOS Question

Firebase not downloading gifs in correct order - iOS

So I have 4 gifs stored using Firebase storage and I am using Realtime Database to fetch their download URLS and append them in an array. The problem is, when I want to download them by iterating through the array, they are not always downloaded in the correct order. In fact, it downloads in a random order each time.

My code so far:

if self.downloadURLS.isEmpty == true {
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
var newItems: [UIImage] = [UIImage]()

for (index, element) in self.downloadURLS.enumerate() {
print("Item \(index): \(element)")
self.storageRef = self.storage.referenceForURL(element)
self.storageRef.dataWithMaxSize(5 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
self.image = UIImage(gifData: data!, levelOfIntegrity: 1)
print("Downloaded \(index)")
newItems.append(self.image)
}
}


self.items = newItems
}
}

print(downloadURLS.joinWithSeparator("\n"))
}


Are there any ways of making sure they download is in the correct order or is there some sort of Sorting method I could use at the end? The last time it finished it downloaded in the order: 2,3,0,1...Any help would be awesome!

Answer

I guess your handler is called asynchronously. I suggest you to declare your newItems array beforehand and add a dispatch_group_t to track when every image has been downloaded:

var newItems = [UIImage?](count: downloadURLS.count, repeatedValue: nil)
let group = dispatch_group_create()

for (index, element) in self.downloadURLS.enumerate() {
    dispatch_group_enter(group)
    self.storageRef = self.storage.referenceForURL(element)
    self.storageRef.dataWithMaxSize(5 * 1024 * 1024) { (data, error) -> Void in
        if (error != nil) {
            // element at this index stays nil
        } else {
            // Set the element at this index
            newItems[index] = UIImage(gifData: data!, levelOfIntegrity: 1)
        }
        dispatch_group_leave(group)
    }
}

// The following gets called asynchronously when every image has been downloaded (or failed to)
dispatch_group_notify(group, dispatch_get_main_queue()) {
    // This will throw an error because newItems is now an array of Optional UIImages
    // It contains nil when there was an error while getting a specific item
    self.items = newItems
}

Also: Is it correct that you assign self.storageRef within the for loop? I believe you should use a local variable instead:

let ref = self.storage.referenceForURL(element)
ref.dataWithMaxSize ...