getting data out of a closure that retrieves data from firebase
That's because when you fetch data from Firebase the call is Asynchronous. What you can do:
Option 1 - Set your logic inside the closure (Like what you have that print the var inside the closure).
Option 2 - Define your own closure that going to receive your data like:
func myMethod(success:([String])->Void){
ref?.observeEventType(.Value, withBlock: { snapshot in
var newNames: [String] = []
for item in snapshot.children {
if let item = item as? FIRDataSnapshot {
let postDict = item.value as! [String: String]
newNames.append(postDict["name"]!)
}
}
success(newNames)
})
}
Option 3 - Use the delegate pattern
protocol MyDelegate{
func didFetchData(data:[String])
}
class MyController : UIViewController, MyDelegate{
func myMethod(success:([String])->Void){
ref?.observeEventType(.Value, withBlock: { snapshot in
var newNames: [String] = []
for item in snapshot.children {
if let item = item as? FIRDataSnapshot {
let postDict = item.value as! [String: String]
newNames.append(postDict["name"]!)
}
}
self.didFetchData(newNames)
})
}
func didFetchData(data:[String]){
//Do what you want
}
}
Retrieve String value from function with closure in Swift
You need to create completion handler like this
func GetUsername(uid:String , completion: (String) -> ()) {
firebase.child("Users").child(uid).observeSingleEventOfType(.Value) { (snapshot:FIRDataSnapshot) in
if let username = snapshot.value!["Username"] as? String
completion(username)
}
else {
completion("")
}
}
And call function like this way
self.GetUsername(str) { (name) -> () in
if name.characters.count > 0 {
print(name)
}
else {
print("Not found")
}
}
Retrieve value from function with swift closure
If I'm understanding the structure/question correctly, your goal is to access the WholeDocument
array in another SwiftUI view. The way to do that could be:
class UserData : ObservableObject {
// Use Firebase library to configure APIs
private var db = Firestore.firestore()
@Published var WholeDocument : Array = []
init() {
db.collection("Users").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
completion([""])
} else {
for document in querySnapshot!.documents {
// print("\(document.documentID) => \(document.data())")
self.WholeDocument.append(document.documentID)
}
}
}
}
}
struct MyContentView : View {
@ObservedObject var database: UserData
var body: some View {
// access database.WholeDocument
List(database.WholeDocument, id: \.self) {
// do something
}
}
That way, when you initialize MyContentView
with an instance of UserData
, you will be able to observe WholeDocument
in that view.
retrieve data from firebase failed
Due to asynchronous operations, there is no value (yet) at your third print statement.
Your first two print statement actually execute after your third print statement even if it doesn't look like it. If you create breakpoints at each print statement, you will be able to see the order of execution.
So to guarantee the data is back from Firebase, you should only be calling the data inside here:
databaseRef?.child("userTable").child(email).observe(.value, with: { (snapshot) in
// Manipulate data here
}
If you prefer the calls to be synchronous, you can do the following:
func retrieveData(user: User) {
//let userID = Auth.auth().currentUser?.uid
let email = user.emailAddress!
// print(email)
databaseRef?.child("userTable").child(email).observe(.value, with: { (snapshot) in
// Get user value
print("whats up ")
if let value = snapshot.value as? [String:String] {
let res = value["posts"]
user.deserialize(data: res!)
if( user === self.u1) {
print("they are same obj") // this will print, so they are pointing to the same address
}
print(self.u1.posts) // this also printed the things I want
}
// ...
})
if( user === self.u1) {
print("they are same obj outside") // this also prints
}
DispatchQueue.main.async{
print(self.u1.posts) // Now called sequentially
}
}
How do I make it such that .observe in Firebase retrieves all its data before calling reload collection view
Try :-
If you are calling for .value as FIRDataEventType only then its possible for you to check the count
let count = snapshot.childrenCount
if self.URLArrayStringRecents.count == Int(count){
self.whatsNewCollectionView.reloadData()
}
Otherwise if you are calling for .childAdded as FIRDataEventType, it will return single snapshot at a time , you can either fix up a NSTimer which waits for a certain time period after calling a .reloadData().
Firebase Observe Closure Not Called
A .childAdded
event is fired for each child node that exist initially, or that is added later. If there are child nodes, .childAdded
is not fired.
If you want to know whether data exists, you should observe the .value
event.
If you observe both .child...
and .value
on the same reference/query, Firebase will only retrieve the data once. So there is no extra data transfer to observe both events.
Also see:
- How do I check if a firebase database value exists?
- Checking if Firebase snapshot is equal to nil in Swift
Related Topics
Xcode 6.1 Missing Required Architecture X86_64 in File
How to Create Layout Constraints Programmatically
One Step Affine Transform for Rotation Around a Point
Objective C: Downloading File with Progress Bar
How to Use Nslocalizedstring Function with Variables in Swift
Scrollview Gesture Recognizer Eating All Touch Events
Capturing and Storing a Picture Taken with the Camera into a Local Database/Phonegap/Cordova/Ios
Uidatepicker Select Month and Year
Custom Init for Uiviewcontroller in Swift with Interface Setup in Storyboard
What Is "Self" Used for in Swift
Xcode Quits Unexpectedly Every Time I Open My Project
How to Delete Wkwebview Cookies
Swift Compiler Shows Expected Declaration Error
Retrieve All Contacts Phone Numbers in iOS
Xcode Beta 6 iOS 8: Simulator Not Working
iOS Uinavigationbar Button Remains Faded After Segue Back
Ibeacon: Didrangebeacons Stops Getting Called, Must Reset Device for It to Work Again