swiftuitableviewswift3loadingpfquery

Activity Indicator While Tableview Loads


In my Xcode project I load items into an Array and then present it on a UITableViewController. While these items load the UITableViewController is empty and is not aesthetically pleasing so I want to put an activity indicator in the UITableViewController while its loading the data. I have copied my code at the bottom. How do I implement this? (I heard something called a completion handler could possibly do the trick but I am not sure how to use it)

func loadAnimals() {
    let animalQuery = PFQuery(className: "Animals")
    animalQuery.whereKey("userID", equalTo: PFUser.current()?.objectId! ?? String()) //getting which user
    animalQuery.limit = 10
    animalQuery.findObjectsInBackground { (objects, error) in
        if error == nil {
            self.colorArray.removeAll(keepingCapacity: false)
            self.animalNameArray.removeAll(keepingCapacity: false)                
            self.animalTypeArray.removeAll(keepingCapacity: false)

            for object in objects! {
                self.colorArray.append(object.value(forKey: "colorType") as! String) // add data to arrays
                self.animalNameArray.append(object.value(forKey: "animalName") as! String) // add data to arrays                    
                self.animalTypeArray.append(object.value(forKey: "animalType") as! String) // add data to arrays
            }
            self.tableView.reloadData()

        } else {
            print(error?.localizedDescription ?? String())
        }
    }
}

//places colors in rows

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! AnimalCell //connects to color cell

    //Adds the animal information in the cells
    cell.colorType.text = colorArray[indexPath.row] 
    cell.animalName.text = animalNameArray[indexPath.row] 
    cell.animalType.text = animalTypeArray[indexPath.row] 

    return cell
}

Solution

  • It seems you have an asynchronous function for loading the table view data. You just need to put activityIndicator.stopAnimating() inside there.

    Add a UIActivityIndicatorView either programatically or through Storyboard to your table view controller. If you choose to do it in code, this is how you do it, including adding constraints to keep it in the middle of your view controller:

    view.addSubview(activityIndicator)
    activityIndicator.translatesAutoresizingMaskIntoConstraints = false
    activityIndicator.hidesWhenStopped = true
    activityIndicator.color = UIColor.black
    let horizontalConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0)
    view.addConstraint(horizontalConstraint)
    let verticalConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0)
    view.addConstraint(verticalConstraint)
    

    Before calling the above code inside viewDidLoad(), declare let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) somewhere in your class.

    You just have to start animating it as soon as loadAnimals starts execution and stop it before calling tableView.reloadData(). Name it `activityIndicator, then do the following:

    func loadAnimals() {
        activityIndicator.startAnimating()
        let animalQuery = PFQuery(className: "Animals")
        animalQuery.whereKey("userID", equalTo: PFUser.current()?.objectId! ?? String()) //getting which user
        animalQuery.limit = 10
        animalQuery.findObjectsInBackground { (objects, error) in
            if error == nil {
                self.colorArray.removeAll(keepingCapacity: false)
                self.animalNameArray.removeAll(keepingCapacity: false)                
                self.animalTypeArray.removeAll(keepingCapacity: false)
    
                for object in objects! {
                    self.colorArray.append(object.value(forKey: "colorType") as! String) // add data to arrays
                    self.animalNameArray.append(object.value(forKey: "animalName") as! String) // add data to arrays                    
                    self.animalTypeArray.append(object.value(forKey: "animalType") as! String) // add data to arrays
                }
                activityIndicator.stopAnimating()
                self.tableView.reloadData()
    
            } else {
                print(error?.localizedDescription ?? String())
            }
        }
    }