Daniel DE
Daniel DE

Reputation: 95

Initialize variables with firebase data on SwiftUI app

this is my first time programming in Swift/SwiftUI and I have been stuck with an issue for the past couple of weeks.

The App I am trying to build an application in which users enter data for a game, this data is stored on their phone, and once the answers are available in a firebase data base it will compare against them and calculate a score.

So far I have been able to: - Integrate firebase into the iOS app - I have been able to run lists / foreach loops on the information gathered from the database

At the moment my issue is the following: I am trying to load the information from firebase, and then use this information to compare against the user data and calculate a score. When I do this the function that returns data from firebase is returning an empty array.

Firebase results function

func getResults() {
        ref.child("eventResults").observe(DataEventType.value) { (snapshot) in
            self.eventResults = []
            for child in snapshot.children {
                if let snapshot = child as? DataSnapshot,
                    let event = EventResults(snapshot: snapshot) {
                    self.eventResults.append(event)
                }
            }
        }
    }

If I run that code in a SwiftUI view with no calculations it pulls and shows the data correctly, here is an example view that works properly

import SwiftUI

struct TestView: View {
    @ObservedObject var session = FirebaseSession()


    var body: some View {

        ZStack {
            Color.init(red: 221/255, green: 221/255, blue: 221/255)
                .edgesIgnoringSafeArea(.all)
            VStack {
                List{
                    //
                    ForEach(self.session.eventResults) { event in

                        HStack() {
                            Text(event.name)
                                .font(.system(size: 30))
                            Spacer()
                            Text("\(event.answer)")
                                .font(.system(size: 30))

                        }

                    }

                }.frame(width: UIScreen.main.bounds.width*0.9)
            }.onAppear() {
                self.getFirebaseData()
            }
        }
    }

    func getFirebaseData() {
        session.getResults()
    }
}

But in another view I am trying to calculate the user score in the background in order to update the user profile with the correct score, I have tried a variety of methods to do this but the initial array always comes up empty.

Below is the sample code I am trying to run


import SwiftUI
import CoreData

struct EventList : View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @ObservedObject var session = FirebaseSession()

    @FetchRequest(entity: UserEvents.entity(),
                  sortDescriptors: [])

    var userEvents: FetchedResults<UserEvents>

    var body: some View {

        ZStack {
            Color.init(red: 221/255, green: 221/255, blue: 221/255)
                .edgesIgnoringSafeArea(.all)
            VStack {
                ScrollView {
                    VStack(alignment: .leading) {
                        ForEach(userEvents) { eventVar in
                                EventCard(eventVar: eventVar)
                                    .cornerRadius(0)
                                    .shadow(color: .black, radius: 5, x: 2, y: 2.0)
                                    .padding(.horizontal)
                                    .frame(width: UIScreen.main.bounds.width)
                        }
                    }
                }
            }
        }.onAppear{
            self.getFirebaseData()
            var testvar2 = self.session.eventResults // is empty
            self.calcScores(resultlist: self.session.eventResults)
        }
    }

    //MARK: calculate Scores

    func getFirebaseData() {
        session.getResults()
    }



    func calcScores(resultlist: [EventResults]) {
          var testcount = resultlist.count // is empty

        }
}

Any help or guidance with this is greatly appreciated, Daniel

Upvotes: 0

Views: 675

Answers (3)

to fix your problem you could try something like this:

func getResults(completion: @escaping () -> Void) {
    ref.child("eventResults").observe(DataEventType.value) { (snapshot) in
        self.eventResults = []
        for child in snapshot.children {
            if let snapshot = child as? DataSnapshot,
                let event = EventResults(snapshot: snapshot) {
                self.eventResults.append(event)
            }
        }
       completion()
    }
}

then call it like this:

session.getResults() {
    // now do something with eventResults
}

Upvotes: 0

Daniel DE
Daniel DE

Reputation: 95

Based on the input from workingdog, I was able to get the code working with a minor variation on the function call

Get Results Function

func getResults(completion: @escaping (_ message: String) -> Void) {
    ref.child("eventResults").observe(DataEventType.value) { (snapshot) in
        self.eventResults = []
        for child in snapshot.children {
            if let snapshot = child as? DataSnapshot,
                let event = EventResults(snapshot: snapshot) {
                self.eventResults.append(event)
            }
        }
       completion("DONE")
    }
}

but I had to modify the function call to the following:

       session.getResults(completion: { message in
               print(message)
// code execution here
        })

Thanks for all the help!

Upvotes: 1

The problem as I see it, is in EventList (and everywhere else) you call self.getFirebaseData() which calls getResults() and that is an asynchronous call. You have to wait till it is finished before you can have:

var testvar2 = self.session.eventResults

Upvotes: 0

Related Questions