UITableView not displaying cells (using swift)
I am using xcode v6.4. I want to show all usernames I receive from AWS DynamoDB as a table. I tried the following code
import UIKit
class messagesTableViewController: UITableViewController {
var myData: Array<AnyObject> = []
override func viewDidLoad() {
super.viewDidLoad()
let exp = AWSDynamoDBScanExpression()
// exp.valueForKey("name")
// exp.scanFilter = [ "date" : cond ]
self.scan(exp).continueWithSuccessBlock({ (task: AWSTask!) -> AWSTask! in
NSLog("Scan multiple values - success")
let results = task.result as! AWSDynamoDBPaginatedOutput
for r in results.items {
let myItem: Item = r as! Item
println(myItem.name)
self.myData.append(myItem.name)
println("\(self.myData)")
}
return nil
})
}
func scan(expression : AWSDynamoDBScanExpression) -> AWSTask! {
let mapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()
return mapper.scan(Item.self, expression: expression)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
println("\(myData.count)")
return myData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellID: String = "cell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellID) as! inboxTableViewCell
dispatch_async(dispatch_get_main_queue(), {
cell.nameLabel.text = self.myData[indexPath.row] as? String
})
return cell
}
Here, the print 'println ("(self.myData)")' command prints the correct data, but the same data is not displayed in a table.
Also, the same code works correctly and displays the cells in the table view when I add static values to the array. For example, below is my code:
import UIKit
class messagesTableViewController: UITableViewController {
var myDummy: Array<AnyObject> = []
override func viewDidLoad() {
super.viewDidLoad()
var i = 1
myDummy = ["Amit", "Kushal", "Saurabh", "Harsh", "Swar"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myDummy.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellID: String = "cell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellID) as! inboxTableViewCell
dispatch_async(dispatch_get_main_queue(), {
cell.nameLabel.text = self.myDummy[indexPath.row] as? String
})
return cell
}
It will be a great help if someone can walk me through this.
source to share
I finally understood. Here's the updated code.
import UIKit
class messagesTableViewController: UITableViewController {
var myData: Array<AnyObject> = []
override func viewDidLoad() {
super.viewDidLoad()
var i = 1
let exp = AWSDynamoDBScanExpression()
// exp.valueForKey("name")
// exp.scanFilter = [ "date" : cond ]
self.scan(exp).continueWithSuccessBlock({ (task: AWSTask!) -> AWSTask! in
NSLog("Scan multiple values - success")
let results = task.result as! AWSDynamoDBPaginatedOutput
for r in results.items {
let myItem: Item = r as! Item
println(myItem.name)
self.myData.append(myItem.name)
println("\(self.myData)")
}
// This is the change in code. It needs to be added because the AWS scan gathers the data in a background queue and we need to get back to the main queue after the background task is completed and then reload the table view.
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
});
return nil
})
}
func scan(expression : AWSDynamoDBScanExpression) -> AWSTask! {
let mapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()
return mapper.scan(Item.self, expression: expression)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
println("\(myData.count)")
return myData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellID: String = "cell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellID) as! inboxTableViewCell
dispatch_async(dispatch_get_main_queue(), {
cell.nameLabel.text = self.myData[indexPath.row] as? String
})
return cell
}
}
The code in the question doesn't work because the AWS scan is collecting data in the background and we need to go back to the main queue after the background task completes and then reload the table view.
source to share
Here's the code that should work:
override func viewDidLoad() {
super.viewDidLoad()
let exp = AWSDynamoDBScanExpression()
self.scan(exp).continueWithSuccessBlock({ (task: AWSTask!) -> AWSTask! in
println("Scan multiple values - success")
let results = task.result as! AWSDynamoDBPaginatedOutput
for r in results.items {
let myItem: Item = r as! Item
println(myItem.name)
self.myData.append(myItem.name)
}
// THIS IS THE CODE YOU NEED TO ADD:
tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: UITableViewRowAnimation.Automatic) // Or choose some other animation.
return nil
})
}
source to share
Try removing the dispatch_async part and change the nameLabel to textLabel, for example:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell") as! inboxTableViewCell
cell.textLabel.text = self.myDummy[indexPath.row] as? String
return cell
}