2
\$\begingroup\$

I'm trying to create an app that is scalable. One of the main features of the app is to view images from a database to a UITableView. Here is my code:

import UIKit

class HomePageTableViewController : UITableViewController {


private var imageObjects: [ImageParseObject] = []
private var skipNumObjects = 0
private var notificationKey = "bananasaregood"

override func viewDidLoad() {
  super.viewDidLoad()
  tableView.rowHeight = UITableViewAutomaticDimension
  tableView.estimatedRowHeight = 320
  loadMoreImages()
  NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshData", name: notificationKey, object: nil)
}


func loadMoreImages() {
  let query = PFQuery(className: "ImagePost")
  query.limit = 25
  query.skip = skipNumObjects
  query.findObjectsInBackgroundWithBlock({
    objects, error in
    if error != nil {
      print(error)
    } else {
      self.imageObjects += self.convertPFObjectsToImageParseObjects(objects!)
    }
  })
  skipNumObjects += 25
}

 func refreshData() {
    tableView.reloadData() 
 }

 func convertPFObjectsToImageParseObjects(pfObjects: [PFObject]) -> [ImageParseObject] {
   var imgObjects: [ImageParseObject] = []
   for i in 0..<pfObjects.count {
     let object = pfObjects[i]
     imgObjects.append(ImageParseObject(imageObject: object, index: i))
  }
  return imgObjects
  }

 }

 extension HomePageTableViewController {

 override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
   return 1
 }

 override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return imageObjects.count
  }

 override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
   let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! HomePageTableViewCell
   let imageParseObject = imageObjects[indexPath.row]
   cell.imagePost.image = UIImage(named: "default")
   cell.imagePost.file = imageParseObject.image
   cell.imagePost.loadInBackground()
   cell.userImage.image = UIImage(named: "default")
   cell.userImage.file = imageParseObject.userImage
   cell.userImage.loadInBackground()
   cell.timeAgo.text = imageParseObject.timeAgo!
   return cell
 }
}

extension HomePageTableViewController {

override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
  if tableView.contentOffset.y >= tableView.contentSize.height - tableView.frame.height {
    print("Reached the end")
    loadMoreImages()
   }
 }
 }

Ideally, I would like this app to have the versatility to scale to thousands of users. So if I have thousands of images in the database it will still run smoothly. I'm not sure if I've accomplish that, that's why I'm asking for review. Do you think this code would fail in large scale?

Basically what I'm doing is I'm storing the objects, ImageParseObject, in an array, (Storing objects aren't as expensive as storing the images) the objects contain references to the actual image files in the database. When I load my tableview I simply reference the file and load them in the background. When I scroll to the end, I loadMoreImages(). The NSNotificationCenter is a start signal, I reload my tableview only after the first ImageParseObject is ready.

\$\endgroup\$
1
\$\begingroup\$

I predict that scrolling in this tableview would be choppy. The problem you are trying to solve is pretty common - for example, find a shopping app that has to display many images of products in a UICollectionView. The scrolling in these UICollectionViews is smooth even though you might be scrolling through hundreds of images. How do they do this?

Here are my suggestions.

1) Find an image caching framework to use like Kingfisher or its Objc predecessor SDWebImage.

2) Parse objects have a URL property (according to their docs).

3) When you populate the tableview, each cell gets configured with its own Parse object. Within each cell, use the image caching frameworks method for setting an image on that cell's image view with that cell's Parse object's url property.

4) Paging - if you have thousands of users, you don't want to download all 50000 at once. Inside cellForRowAtIndexPath, you should check the current row against the data source array of the table view and see if you're about to run out of data to display, and when that happens, eg (row <= data.count - 4) call your fetch method for more Parse data.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.