ios - 目前如何在 Swift 中进行观察?
问题描述
我在这段代码中有一个问题:
func calculaGastos() -> Float{
let idUser = Auth.auth().currentUser?.displayName
var total : Float = 0
let ref = Database.database().reference().child("Users").child(idUser!).child("Gastos")
ref.observeSingleEvent(of: .value) { (snapshot) in
let value = snapshot.value as? NSDictionary
if(value != nil){
for i in value!{
let j = i.value as? NSDictionary
let precio = j?["precio"] as? Float
let fecha = j?["Fecha"] as? String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d, yyyy"
let date = dateFormatter.date(from: fecha!)
if(((date?.timeIntervalSinceNow)! * -1) < (30*24*3600)){
print("Total:" ,total)
total += precio!
}
}
}
print("Calculing in the function", total)
}
return total
}
在另一个视图控制器的覆盖函数中调用它,日志显示在 viewdidload 的打印中为 0,但在函数 print 中显示打印为 30 但始终返回 0,我认为问题在于它在进入观察者之前返回,但我不确定有什么解决方案?
override func viewDidLoad() {
super.viewDidLoad()
nomUser.text = id?.displayName!
correoLabel.text = id?.email!
print("Calculing in View Controller", calculo.calculaBenef(), calculo.calculaGastos())
gastosField.text = String(calculo.calculaGastos())
benefField.text = String(calculo.calculaBenef())
// Do any additional setup after loading the view.
}
这是我的日志: 日志
解决方案
在我目前正在开发的应用程序中,我遇到了类似的问题。解决方案是在函数中实现一个调度组。我还更改了函数返回的方式total
,以便它现在由完成处理程序返回。
试试这个:
func calculaGastos(completionHandler: @escaping (Float) -> Void){
let idUser = Auth.auth().currentUser?.displayName
var total : Float = 0
let ref = Database.database().reference().child("Users").child(idUser!).child("Gastos")
ref.observeSingleEvent(of: .value) { (snapshot) in
let value = snapshot.value as? NSDictionary
if(value != nil){
let myGroup = DispatchGroup()
for i in value!{
myGroup.enter()
let j = i.value as? NSDictionary
let precio = j?["precio"] as? Float
let fecha = j?["Fecha"] as? String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d, yyyy"
let date = dateFormatter.date(from: fecha!)
if(((date?.timeIntervalSinceNow)! * -1) < (30*24*3600)){
print("Total:" ,total)
total += precio!
}
myGroup.leave()
}
myGroup.notify(queue: .main) {
print("Calculing in the function", total)
completionHandler(total)
}
}}
}
调用函数并total
像这样使用:
override func viewDidLoad() {
super.viewDidLoad()
nomUser.text = id?.displayName!
correoLabel.text = id?.email!
print("Calculing in View Controller", calculo.calculaBenef())
calculo.calculaGastos { (total) in
print("calculaGastos total: \(total)")
gastosField.text = String(total)
benefField.text = String(calculo.calculaBenef())
}
// Do any additional setup after loading the view.
}
据我了解:
observeSingleEvent
return
是异步的,因此它可能会在调用时完成,也可能不会完成。此外,for i in value
仅在observeSingleEvent
完成后才开始,因此return
更有可能在任务完成之前被调用。这就是DispatchGroup()
完成处理程序的用武之地。
当myGroup.enter()
被调用时,它会通知 DispatchGroup 一个任务已经开始。调用时myGroup.leave()
,会通知 DispatchGroup 任务已完成。一旦有 s 和 s 一样多.leave()
,.enter()
这个组就结束了。然后myGroup
通知主队列该组已完成,然后completionHandler
调用返回总计。
由于您使用calculaGastos
. 您正在调用该函数,然后您将使用返回值显示在文本字段中。现在添加了完成处理程序,textField.text
只有在完成后才设置calculaGastos
并返回total
:
calculo.calculaGastos { (total) in
print("calculaGastos total: \(total)")
gastosField.text = String(total)
benefField.text = String(calculo.calculaBenef())
}
希望这有点道理!很高兴代码对你有用。
推荐阅读
- suitecrm - 检测日期字段suitecrm的变化
- linux - 如何从精灵中提取枚举信息?
- java - 我必须制定球队之间的比赛时间表
- azure - 使用 AzureADB2C 和 B2B 进行单点登录
- java - 如何实现接口内联而不是在 Dart/Flutter 中使用类?
- python - 基本python密码保险库,答案重复不停等问题
- android - 在 ImageView 上设置后获取 drawable 的名称
- regex - 正则表达式 [ 1 ( 0 1* 0)* 1 ]* DFA
- javascript - 使用辅助 JS 文件在 Vue 和 Laravel 中嵌入 Typeform
- powershell - 我们可以添加等待进程完成的最长时间吗?