-1

So, in my code, you can see that I want to return the information that I retrieve from Firebase, but always the method returns an empty array, I'm new to Swift, can you please explain why this is happening and how can I make it work? Thanks a lot.

var catalog:[String:NSDictionary] = [String():NSDictionary()]
func readCatalogInfo()->[String:NSDictionary]{
    
    let ref = Database.database(url: "https://reforestar-database-default-rtdb.europe-west1.firebasedatabase.app/").reference()
    
    _ = ref.child("trees").observe(.value, with: {snapshot in
        
        guard let information:[String:NSDictionary] = snapshot.value as? [String:NSDictionary] else {
            print("Error in getting information about the Trees")
            return
        }
        self.catalog = information
        
    })
    
    return self.catalog
}

Here's a pic of the code if you want to see it

bravemoon
  • 47
  • 7
  • Does this answer your question? [Returning data from async call in Swift function](https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function) – Joakim Danielson May 24 '21 at 19:21
  • There'a a great answer by @vadian which may be the solution. Note there are a number of ways to accomplish this, with a completion handler being one of them. If you are going to use the data at a later time, like in a catalog, then populating it within the Firebase closure and not attempting to return it would also work. For example; if a user logs in and at some point thereafter they want to look up a part in their catalog. That catalog could be pre-loaded when they log in. We don't know your specific use case so consider how that data will be used to then determine a solution. – Jay May 25 '21 at 15:44

1 Answers1

1

The database request work asynchronously, you have to add a completion handler.

And don't use NS... collection types in Swift

var catalog = [String:[String:Any]]()

func readCatalogInfo(completion: @escaping ([String:[String:Any]]) -> Void) {
    
    let ref = Database.database(url: "https://reforestar-database-default-rtdb.europe-west1.firebasedatabase.app/").reference()
    
    _ = ref.child("trees").observe(.value, with: {snapshot in
        
        guard let information = snapshot.value as? [String:[String:Any]] else {
            print("Error in getting information about the Trees")
            return
        }
        completion(information)
        
    })
    
}

And use it

readCatalogInfo() { [weak self] result in 
   self?.catalog = result
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks for the response but it still not working, the self.catalog is a variable that will be available through all the view controller, when I exist the method I get an empty array ... – bravemoon May 27 '21 at 18:13
  • I get it, I can only use the information inside the readCatalogInfo() method, but is there any way that I can use the information outside of it, keeping the info on a global variable or the cache, as i told you, I'm new to Swift, so this could be usefull. @vadian ?? :) – bravemoon May 27 '21 at 18:22
  • Run the code you need to run inside the closure. – vadian May 27 '21 at 18:27