Luke Patterson Luke Patterson - 7 months ago 10
Swift Question

Swift variable still 0 after assigning it a value?

in my viewDidLoad() i print out a the result of a function

override func viewDidLoad() {
super.viewDidLoad()
print("top count = \(getCurrentOrderNum())")
}


The function computes the value likes so

func getCurrentOrderNum() -> Int{
var orderNum = 0
ref = Firebase(url: "urlhiddenforprivacy")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
let count = snapshot.childrenCount
orderNum = Int(count)
})
return orderNum
}


Yet it still prints 0? I tried to put var orderNum: Int = Int() at the top of my code instead of inside my getCurrentOrderNum function, but that didn't work. I know it gets the correct value inside my ref.observe function because when I ran this... it printed out the right value

ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
let count = snapshot.childrenCount
orderNum = Int(count)
print(orderNum) //*****THIS PRINTS THE RIGHT VALUE****
})
return orderNum
}

Answer

You are returning orderNum from the method getCurrentOrderNum() before the asynchronous block actually runs. So at the time of return, orderNum is still 0, the initial value you set. The block completes later.

Your best option is probably to change the method to:

func getCurrentOrderNum(callback:Int->()) {
    var orderNum = 0
    ref = Firebase(url: "urlhiddenforprivacy")
    ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
        let count = snapshot.childrenCount
        orderNum = Int(count)
        callback(orderNum)
    })
}

And you would then call it like this:

override func viewDidLoad() {
    super.viewDidLoad()
    getCurrentOrderNum { orderNum in print(orderNum) }
}

This changes the getCurrentOrderNum() method to call back to a closure once it has finished retrieving the right value.

UPDATE: Based on comment below, the goal it to do something like this:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int { 
    return getCurrentOrderNum() 
}

Here is an asynchronous approach for doing that:

class YourViewController : UIViewController, UITableViewDataSource {

    private var orderNumber:Int = 0
    private IBOutlet var tableView:UITableView!

    func getCurrentOrderNum(callback:Int->()) {
        ref = Firebase(url: "urlhiddenforprivacy")
        ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
            let count = snapshot.childrenCount
            callback(Int(count))
        })
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        getCurrentOrderNum {
            orderNum in
            //This code runs after Firebase returns the value over the network
            self.orderNumber = orderNum  // Set our orderNumber to what came back from the request for current order number
            self.tableView.reloadData()  // Now reload the tableView so it updates with the correct number of rows
        }
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {    
        return self.orderNumber // When the view first loads, this will be 0 and the table will show nothing.  After the request to Firebase returns the value, this will be set to the right number, the table view will be reloaded, and it will call this method again to get the updated number of rows to display.
    }
}
Comments