1

I have class getDataFromDatabase which has func readData() thats read data from Firebase.

class getDataFromDatabase : ObservableObject {

    var arrayWithQuantity = [Int]()
    var arrayWithTime = [Double]()
    
    func readData(completion: @escaping(_ getArray: Array<Int>?,_ getArray: Array<Double>?) -> Void) {
       
        let db = Firestore.firestore()
        
        db.collection("amounts").getDocuments { (querySnapshot, err) in
            
            if let e = err{
                print("There's any errors: \(e)")
            }
            
            if err != nil{
                print((err?.localizedDescription)!)
                return
            }
            
            for i in querySnapshot!.documents{
                
                let quantityFromDb = i.get("amount") as! Int
                let timeFromDb = i.get("averageTimeRecognition") as! Double
                
                
                self.arrayWithQuantity.append(quantityFromDb)
                self.arrayWithTime.append(timeFromDb)
            }
            completion(self.arrayWithQuantity, self.arrayWithTime)
        }
    }
}

I use func readData() in onAppear:

struct CheckDatabaseView: View {
    
    @State private var quantityFromDatabase: Array<Int> = []
    @State private var timeFromDatabase: Array<Double> = []
    @State private var flowersName: Array<String> = ["Carnation", "Daisy", "Hyacinth", "Iris", "Magnolia", "Orchid", "Poppy", "Rose", "Sunflower", "Tulip"]
    @State private var isReady: Bool = false
    
    
    var body: some View {
        
        ScrollView(.vertical, showsIndicators: false){
            ZStack(alignment: .top){
                VStack(spacing: 40){
                    Text("Hello, world!")
//                    BarView(value: CGFloat(timeFromDatabase[0]), name: flowersName[0])
                    
                }
            }
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top)
            
        }
        .navigationBarTitle(Text("Your datas in database").foregroundColor(.blue), displayMode: .inline)
        .onAppear{
            
            let gd = getDataFromDatabase()
            gd.readData { (quantity, time) in
                self.quantityFromDatabase = quantity!
                self.timeFromDatabase = time!       
            }
        }
    }
}

I cannot use values self.quantityFromDatabase and self.timeFromDatabase because are empty. I know the problem is with the asynchronous retrieval of data. I've tried with DispatchQueue.main.async, but I still not get these values. How is the other method to get it? I need this values, because I want to draw charts in VStack (the comment line there).

EDIT

As @Rexhin Hoxha wrote below, i modified the code but i am not sure if the way is correct. I changed var arrayWithQuantity = [Int]() and var arrayWithTime = [Double]() by adding @Published in class getDataFromDatabase (now it's GetDataFromDatabaseViewModel):

class GetDataFromDatabaseViewModel : ObservableObject {

    @Published var arrayWithQuantity = [Int]()
    @Published var arrayWithTime = [Double]()
    
    func readData() {
       
        let db = Firestore.firestore()
        
        db.collection("amounts").getDocuments { (querySnapshot, err) in
            
            if let e = err{
                print("There's any errors: \(e)")
            }
            
            if err != nil{
                print((err?.localizedDescription)!)
                return
            }
            
            for i in querySnapshot!.documents{
                
                let quantityFromDb = i.get("amount") as! Int
                let timeFromDb = i.get("averageTimeRecognition") as! Double
                
                
                self.arrayWithQuantity.append(quantityFromDb)
                self.arrayWithTime.append(timeFromDb)
            }
            print("Array with quantity: \(self.arrayWithQuantity.count)")
        }
    }
}

also in struct I initialized @ObservedObject var gd = GetDataFromDatabaseViewModel() and onAppear now looks like this:

.onAppear{
            
            self.gd.readData()
            print("Quantity after reading: \(self.gd.arrayWithQuantity.count)")
        }

but print in onAppear still print an empty Array. Where did I do a mistake?

1
  • I can not test your code right now but I know one thing for sure. You do not need to use DispatchQueue.main.async because Firebase calls run in the main thread. Commented Aug 9, 2020 at 19:28

1 Answer 1

2

So the problem is in your completion handler. It returns before you retrieve the data.

Solution is to make your arrays @Published and read the data in real time from the view. You have to remove the completion handler.

Call the function on ‚onAppear()‘ and use @ObservedObject to bind to your ViewModel (getDataFromDatabase). This is how it’s done in SwiftUI.

Please capitalize the first letter and use something more generic like „YouViewName“ViewModel.

Your name is fine for a method/function but not for a Class

Sign up to request clarification or add additional context in comments.

13 Comments

Hey, thank you for your response! I edited the post, could you look on it? I'm sure that I did a mistake, but I don't know where
Oh ok, I understand now... Thank you for your help I will try to find a solution to this problem on the internet. I hope there is any way to solve this problem
I will read up about async calls and maybe will find any solution. Thank you!
add the array instead of the range. the foreach will update whenever new elements are appended there. again 1...5 will try to print the elements but in async call the elements come later. you can bot do that unless you are extremely sure the element is already there.
Thank you for your help. I did something other - I just created if(array.count != 0) then set value in Text(). It works fine now, thank you for your time and useful tips!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.