Vikram Hegde
Vikram Hegde

Reputation: 91

How to delay a return call in Swift

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

Answers (2)

Rob
Rob

Reputation: 437552

I would:

  1. 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.

  2. 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.

  3. 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

Charles A.
Charles A.

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

Related Questions