Reputation: 95
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
Reputation: 37005
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
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
Reputation: 37005
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