0

The original function is meant to look like this:

func retrieveMonthlySpent(month:String, year:String) -> Double {
    FirebaseFunctions().retrieve(from: .expense, username: self.username as! String, returning: Expenses.self) { (expenses) in
        self.monthlyExpenses = expenses
    }

    var sum:Double = 0
    for expense in self.monthlyExpenses{
        if expense.modificationDate.convertToMonth() == month && expense.expense && expense.modificationDate.convertToYear() == year {
            sum += expense.convertedAmount
        }
    }

    return sum
}

But then the monthly expenses value wouldn't be updated because of the way sync functions work in Swift. So then I tried to change my code so that I put as much code into the async function itself and it looked like this:

func retrieveMonthlySpent(month:String, year:String) -> Double{
    FirebaseFunctions().retrieve(from: .expense, username: self.username as! String, returning: Expenses.self) { (expenses) in
        self.monthlyExpenses = expenses
        var sum:Double = 0
        for expense in self.monthlyExpenses{
            if expense.modificationDate.convertToMonth() == month && expense.expense && expense.modificationDate.convertToYear() == year{
                sum += expense.convertedAmount
            }
        }
    }
    return sum
}

But the problem is that now the value of "sum" is 0 because I use a variable outside this async function. I have seen the issue been raised on multiple questions but I can't find an answer anywhere. What is the solution to this problem

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Arnav GUPTA
  • 295
  • 1
  • 2
  • 17

2 Answers2

1

Use completion handler as a trigger update UI when your data fetched.

Setup function with completion handler :

func retrieveMonthlySpent(month:String, year:String, completion: ((Double) -> Void)? = nil) {
FirebaseFunctions().retrieve(from: .expense, username: self.username as! String, returning: Expenses.self) { (expenses) in
    self.monthlyExpenses = expenses
    var sum = 0.0
    for expense in self.monthlyExpenses {
        if expense.modificationDate.convertToMonth() == month && expense.expense && expense.modificationDate.convertToYear() == year {
            sum += expense.convertedAmount
        }
    }
    completion(sum)
  }
}

Use it in a viewController, for example :

func retrieveMonthlySpent(month:"05", year:"1996") { result in
      self.sumLabel.text = result
}

easy as the way Thanos snaps his fingers :)

Tung Vu Duc
  • 1,552
  • 1
  • 13
  • 22
0

If you are calling the async API then you have to use completion handler:

func retrieveMonthlySpent(month:String, year:String, success: @escaping (Double) -> Void) {
    FirebaseFunctions().retrieve(from: .expense, username: self.username as! String, returning: Expenses.self) { (expenses) in
        self.monthlyExpenses = expenses
        var sum:Double = 0
        for expense in self.monthlyExpenses{
            if expense.modificationDate.convertToMonth() == month && expense.expense && expense.modificationDate.convertToYear() == year{
                sum += expense.convertedAmount
            }
        }
        success(sum)
    }
}

You can use this method from your current controller like that:

self.retrieveMonthlySpent(month: "", year: "") { (sum) in
            print(sum)
        }

Or from other ViewController, you can use like that:

Xviewcontroller().retrieveMonthlySpent(month: "", year: "") { (sum) in
            total = sum
        }

For better code re-usability, You need to put this method on superviewcontroller or in an any common class.

Jogendar Choudhary
  • 3,476
  • 1
  • 12
  • 26