Reputation: 11
The one thing I never really understood when learning Swift was closures. I always find it quite confusing to work with them.
Could someone please explain what I have done false in the code below.
for id in myCircles{
var circleName = ""
var circleCategory = ""
var circleID = ""
ref.child("\(id)").observeSingleEvent(of: .value, with: { snapshot in
let value = snapshot.value as? NSDictionary
circleName = value?["name"] as? String ?? ""
circleCategory = value?["category"] as? String ?? ""
circleID = value?["id"] as? String ?? ""
self.defaults.setValue([circleName, circleID, circleCategory], forKey: "newestCircle"+"\(id)")
}) { error in
}
//the problem is that the part below gets executed before the closure, which is when the value should be added. The part below must be executed after the closure.
let retrievedData = self.defaults.value(forKey: "newestCircle"+"\(id)") as? [String] ?? ["","",""]
self.addCircle(circleName: retrievedData[0], circleID: retrievedData[1], circleCategory: retrievedData[2])
}
As the comment says, my .observingSingeEvent closure is called after the code beneath the closure. Not only is it called after the code below the closure, but it is called after the entire for-loop, as many times as it would have been called, had it been called inside of the loop. I don't understand why this is, can someone please help me?
Upvotes: 1
Views: 689
Reputation: 7173
Closures are just anonymous functions. There's no difference between
func sum(_ a: Int, _ b: Int) -> Int {
a + b
}
and
let sum: (Int, Int) -> Int = { a, b in a + b }
These are both functions that do the exact same thing, sum two integers together, but they're expressed in different forms, one as a function and one using closure syntax and both are interchangeable. The big difference between them is that the function is named and the closure is anonymous. We've stored the closure in a variable called sum
but the closure itself has no name.
For your specific question, I have not used Firebase but what's happening is this call
ref.child("\(id)").observeSingleEvent(of: .value, with: { snapshot in
let value = snapshot.value as? NSDictionary
circleName = value?["name"] as? String ?? ""
circleCategory = value?["category"] as? String ?? ""
circleID = value?["id"] as? String ?? ""
self.defaults.setValue([circleName, circleID, circleCategory], forKey: "newestCircle"+"\(id)")
}) { error in
}
is executing asynchronously. ref.child.observeSingleEvent
takes a closure as a parameter and calls it later which means the execution of the closure is completely separate from the rest of your code. That's why you're seeing things print out of sync, because the closure is executing asynchronously.
As an aside, try to avoid using NSDictionary
unless you absolutely have to and instead of closures, use the new Swift concurrency features for async work.
Upvotes: 1