0

I'm a super beginner at swift. these days I have learned how to use firebase in my project. Basically, I prefer to make simple and short functions always in order to use it in the main code. so I made a function that will return the array value from firebase JSON data. But it always shows the empty, not any data.

Below is apart of my code.

class FunctionList: NSObject {
    var ref : fatabaseReference!
    var db : Database.database().reference()

    func CallInfo() -> (Date:Array<String>, Temper:Array<Float>){
        var _date: [String] = []
        var _temper: [Float] = []

        db.child("Location").observeSingleEvent(of: .value){ snapshot in
            var call: [String] = []
            do{
                let data = try JSONSerialization.data(withJSONObject: snapshot.value, option:[])
                let decoder = JSONDecoder()
                let _site: [Location] = try decoder.decode([Location].self. from:data)
                self._site = _site

                if( _site[0].name == "Newyork"){
                    let Target = _site[0].TemperInfo
                    let lastNum:Int = Target.count
                    let startNum:Int = lastNum-5
                    for i in stride(from startNum, to:lastNum, by: +1){
                        _date.append(Target[i].Date)
                        _temper.append(Target[i].Temper)
                    }
                }
            } catch let error{
                print(" Error has occurred : \(error.localizeDescription)")
                debugPrint(error)
            }
        }
        //for i in stride(from: 0, to:5, by+1){
        //  print("\(_date[i])    \(_temper[i]) )
        //}
        return(_date, _temper)
    }

struct Location: Codable{
    let id:String
    let name: String
    let TemperInfo: [T_Info]
    var toDictionary: [String: Any]{
        let tInfoArray = TemperInfo.map{$0.toDictionary}
        let dict: [String: Any] = ["id":id, "name":name, "TemperInfo":tInfoArray]
        return dict
    }
    static var id: Int = 0    
}

struct T_Info: Codable{
    let Date: String
    let Temper: Float
    var toDictionary:[String: Any]{
        let dict: [String: Any] = ["Date": Date, "Temper":Temper]
        return dict
    }
}

I already check the condition of JSON data in my firebase many time. there clearly exist the data. and I expected the latest 5 days date and temperature via this function. But return always "0". ( I commented out the print line at the above return line of the "CallInfo" function.)

Am I miss something? or is there a more good way to return the array that I want?

Really appreciate your help. Thanks!

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
orde.r
  • 521
  • 2
  • 5
  • 13
  • 1
    `observeSingleEvent` is asynchronous and returns immediately, before the query is complete. If you log something just before the return, you'll see that. – Doug Stevenson Dec 18 '20 at 05:53
  • Okay, then is there any way to get that data as an array? – orde.r Dec 18 '20 at 06:50
  • You should be getting it in the callback. You won't be able to return it directly from `CallInfo`, as the callback is invoked asynchronously. – Doug Stevenson Dec 18 '20 at 07:01

1 Answers1

1

As @Doug mentioned, observeSingleEvent, in fact nearly all fetching from remote, is asyncchronous. Meaning that the function terminates before the data arrives thus you can't return the data directly.

You should use pass in a function as an argument (usually called callback or completion of callInfo (and it's convention to name functions in lower camelcase), and pass the data as the argument of the callback. E.g.

func callInfo(completion: @escaping (Date:Array<String>, Temper:Array<Float>) -> Void) -> {
    // ... do your data fetching

    // now the data is ready, call the handling function with data
    completion(_date, _temper)
}

// Usage
callInfo(completion: { (date, temper) in 
    // the following two lines will execute when the data is ready
    print(date)
    print(temper)
})
Eric Hua
  • 976
  • 2
  • 11
  • 29