Reputation: 91
Hello guys I am currently working on a program that holds a list of books in a UITableView. As you know, the TableView takes two methods, one with cellForRowAtIndexPath and the one I will be talking about today, numberOfRowsInSection. So the problem I am having is that I access my database to get the number of books that are currently in the database in order to return how many indices I will need in the array of Book stucts. So I have two groups, buy and sell, that may or may not have any books in them.
Anyway, I populate my array (it's empty to start with) and then I return the books.count as the numberOfRowsInSection. The problem is that I am consistently returning 0 seeing as the array gets populated after the return is executed.
Below is my code.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
populateArray()
print("books.count: ",books.count)
return books.count // KEEPS RETURNING 0 BC IT HASN'T POPULATED YET *ARRRRRRGH*
}
func populateArray(){
print("started looking")
var indices = 0
if divider.selectedSegmentIndex == 0{
ref.child(school).observeEventType(.Value, withBlock: { (snapshot) in
let numSelling = snapshot.value!["numSelling"] as! Int // gets numSelling
if numSelling > 0 {
self.noEntries = false
print("numSelling: ", numSelling) //see console
indices = numSelling
}else{
self.noEntries = true
indices = 1
print("No Values Selling")
}
}) { (error) in
print(error.localizedDescription)
}
}else{
ref.child(school).observeEventType(.Value, withBlock: { (snapshot) in
let numBuying = snapshot.value!["numBuying"] as! Int // gets numBuying
if numBuying > 0 {
self.noEntries = false
print("numBuying: ", numBuying) //see console
indices = numBuying
}else{
self.noEntries = true
indices = 1
}
}) { (error) in
print(error.localizedDescription)
}
}
delay(0.5){
print("ind: ", indices) // printing correctly
if(self.noEntries){ // just add one book to get the indices to be 1
self.books.append(Book(isbn: "", title: "", author: "", edition: "", price: "", uid: ""))
return
}
if self.divider.selectedSegmentIndex == 0{
self.ref.child(self.school).child("selling").observeEventType(.Value, withBlock: { (snapshot) in
let booksJSON = snapshot.value! as! NSArray
for bookJSON in booksJSON { // add the book to the array
let tempAuthor = bookJSON["authors"] as! String
let tempTitle = bookJSON["title"] as! String
let tempEdition = bookJSON["edition"] as! String
let tempPrice = bookJSON["price"] as! String
let tempISBN = bookJSON["isbn"] as! String
let tempUID = bookJSON["uid"] as! String
self.books.append(Book(isbn: tempISBN, title: tempTitle, author: tempAuthor, edition: tempEdition, price: tempPrice, uid: tempUID))
}
}) { (error) in
print(error.localizedDescription)
}
}else if self.divider.selectedSegmentIndex == 1{
self.ref.child(self.school).child("buying").observeEventType(.Value, withBlock: { (snapshot) in
let booksJSON = snapshot.value! as! NSArray
for bookJSON in booksJSON { // add the book to the array
let tempAuthor = bookJSON["authors"] as! String
let tempTitle = bookJSON["title"] as! String
let tempEdition = bookJSON["edition"] as! String
let tempPrice = bookJSON["price"] as! String
let tempISBN = bookJSON["isbn"] as! String
let tempUID = bookJSON["uid"] as! String
self.books.append(Book(isbn: tempISBN, title: tempTitle, author: tempAuthor, edition: tempEdition, price: tempPrice, uid: tempUID))
}
}) { (error) in
print(error.localizedDescription)
}
}
}
}
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
Keep in mind that I cannot make a callback in this method because it is automatically called by the program when the view is loaded.
Also, the delay segments are in efforts to stop the same thing from happening. Problem is that I cannot put the delay around the return because it thinks I want to return an Int for the delay block.
Console:
started looking
books.count: 0
started looking
books.count: 0
started looking
books.count: 0
started looking
books.count: 0
numSelling: 6
numSelling: 6
numSelling: 6
numSelling: 6
ind: 6
ind: 6
ind: 6
ind: 6
As you can see it is returning 0 before it even gets to the numSelling value from the database.
Thank you so much for your help and have a great day!
Upvotes: 2
Views: 991
Reputation: 437552
I would:
Move the "retrieve titles being bought/sold" out of the delay
method. Call that from within the respective observeEventType
of numSelling
/numBuying
. Get rid of the delay
.
As Charles says, don't worry that the values are empty when viewDidLoad
finishes. Just have the routine call tableView.reloadData()
when it's done.
Assuming your UI is showing both titles being bought and sold at the same time (or that you're jumping between them quickly and don't want to wait for the data to be retrieved), your routine might want to go ahead and retrieve both arrays and only call reloadData
when both are done. This means that you might need two arrays in your model, one for booksSelling
and one for booksBuying
.
Upvotes: 1
Reputation: 11123
You cannot delay returning to a method once it has been called, but you can ask the table view to call the data source methods again.
The easiest solution would be to call reloadData()
on your table view once your data has been populated (i.e., at the end of your populateArray()
method). I would probably also move the call to populateArray()
somewhere else (perhaps viewDidLoad()
, if that's appropriate).
Upvotes: 2