I recently asked this question: Populating a UITableView in Firebase a Set Number of Cells at a time
But through the discussion I realized that the question was actually two questions, so I'm going to start a second thread for the second question:
Is there a way people generally populate tableviews of images from large data sets using Firebase?
Below is the code I'm using for retrieving images. The images are base64 encoded NSStrings.
NSString* profPicString= [child.value objectForKey: @"profilePicture"];
NSData *dataFromBase64=[NSData base64DataFromString:profPicString];
UIImage *profPicImage = [[UIImage alloc]initWithData:dataFromBase64];
item.profilePicture = profPicImage;
The images, however, take a long time to download. A tableview of just 10 images will take 5 or 10 seconds to load. If it's like this with 10 images, it will be truly glacial with hundreds or thousands.
I doubt I'm the first person to encounter this issue, and I was wondering if there's a better/more efficient way of doing it?
Thanks for the help!
If you're going to store your images as base64 encoded strings, store them in a separate location in the Firebase database.
{
"pokemon": {
"001": {
"name": "Bulbasaur"
},
"002": {
"name": "IvySaur"
}
},
"images": {
"001": "big-ole-base64-string",
"002": "big-ole-base64-string"
}
}
This way you can load the main data without needed to pull down the images.
Now when you load your data for your UITableView
, create a listener for the main set of data, /pokemon
in this case.
Then when you get to tableView(_:cellForRowAtIndexPath)
, create a one-time listener to grab the image.
This example is in Swift, but you can convert to Objective-C.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PokeCell") as! PokeTableViewCell
let pokeSnap = pokemonSnaps[indexPath.item]
let imageRef = rootRef.childByAppendingPath("images").childByAppendingPath(pokeSnap.key)
imageRef.observeSingleEventOfType(.Value) { (imageSnap: FDataSnapshot!) in
let base64String = imageSnap.value as! String
let decodedData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))
let image = UIImage(data: decodedData!)
cell.pokeImage.image = image
}
return cell
}
The beauty of this method is that you only load the images when needed, not with the main set of data.