Search code examples
swiftalamofireswifty-json

UITableView got rendered before data from API returned using SwiftyJSON and Alamofire


when I call callapi() function in viewDidLoad(), the println() in callapi prints the posts array with Post objects inside it, however the println() inside the viewDidLoad() function prints an empty array. Also when I build the project I get this error "fatal error: Array index out of range". the println() statement in the tableView function prints an empty array also. It seems the table got rendered before the data from the API arrived how can I solve this?

var posts = [Post]()

override func viewDidLoad() {
    super.viewDidLoad()
    callapi()
    println(self.posts)
}

func callapi(){
    request(.GET, "url")
    .responseJSON { (request, response, data, error) in
        let json = JSON(data!)
        if let jsonArray = json.array {
            for post in jsonArray {
                var onepost = Post(id:post["id"].stringValue,                    

              title:post["title"].stringValue, 
              author:post["author"].stringValue, 
              post:post["post"].stringValue,   
              created_on:post["created_on"].stringValue, 
              updated_on:post["updated_on"].stringValue)
                self.posts.append(onepost)
                println(self.posts)
                self.tableView.reloadData()
            }
        }
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath
 indexPath: NSIndexPath) -> UITableViewCell {
    let cellIdentifier = "Cell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier,
    forIndexPath: indexPath) as! CustomTableViewCell

    println(self.posts)
    let post = self.posts[indexPath.row]
    // Configure the cell...
    cell.titleLabel!.text = self.posts[indexPath.row].title
    cell.postLabel.text = post.post
    println(self.posts)
    return cell
}

Solution

  • When viewDidLoad is called, it starts the asynchronous callapi, but by the time viewDidLoad finishes, posts is still empty. But the table view is still going to proceed with its initial load process, even though posts hasn't been populated, so you must ensure that tableView:numberOfRowsInSection: returns zero at this point.

    Later, callapi finishes the Alamofire GET request and calls reloadData. Only at this point should tableView:numberOfRowsInSection: return non-zero value.

    Bottom line, make sure that tableView:numberOfRowsInSection: returns the actual number of entries in posts, and the problem should be resolved.