0

I'm fairly new to Swift so my apologies if this is something obvious, but so far I have not found an answer.

So, I'm trying to show a list of "friends" in a view and that data comes from a Firebase Realtime Database. The data is being pulled but it gets pulled after the function is finished running.

I also tried to make it work with await async, but the firebase methods don't support that as far as I saw while trying.

If you look at the function bellow, the view and the print outputs, you'll see what I mean by that.

This is the get friends function in my firebase controller file:

func getFriends(completion: @escaping ([Friend])-> Void) {
        print("start getFriends")
        self.friends = []
        let ref = Database.database().reference(fromURL: "users")
        
        ref.queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
             print("entering data snapshot pull")
            let snapshotValue = snapshot.value as! [String:[String:[String:AnyObject]]]
               
                for (key, _) in snapshotValue {
                    for (_, value) in snapshotValue[key]! {
                        var email = ""
                        var userName = ""
                        var id = ""
                        for (key, value) in value {
                            switch key{
                                case "email":
                                    email = value as? String ?? ""
                                case "userName":
                                    userName = value as? String ?? ""
                                case "id":
                                    id = value as? String ?? ""
                                default:
                                    print("")
                            }
                    }
                        print("--------------------------")
                        print(userName)
                        print(email)
                        print(id)
                        self.friends.append(Friend(userName: userName, email: email, id: id))
                }
            }
             print("leaving data snapshot pull")
             
        }
        print("end getFriends")
        completion(friends)
      }

This is my view:

struct ChatListView: View {
    typealias Friend = ChatList<String>.Friend
    @State var friends : [Friend] = []
    @ObservedObject var chatListUI: ChatListUI
    var firebaseController = FirebaseDatabaseController()
    var body: some View {
        Button(action: {
            do {
                try Auth.auth().signOut()
            }
            catch {
                print("cant log out")
            }
        }, label: {
            Text("Log out")
        })
        List {
            ForEach(friends) { Friend in
                Text(Friend.userName)
            }
        }.onAppear(perform: {
            print("start onAppear in view")
            firebaseController.getFriends(){ productsArray in
                self.friends = productsArray
            }
            print("friends count:")
            print(friends.count)
            print("end onAppear  in view")
        })
    }
}

and this is the output:

2022-01-05 13:20:32.273898+0100 ChatBuddy[2094:38382] [error] warning:  View context accessed for persistent container ChatBuddy with no stores loaded
CoreData: warning:  View context accessed for persistent container ChatBuddy with no stores loaded
start onAppear in view
start getFriends
end getFriends
friends count:
0
end onAppear  in view
2022-01-05 13:20:32.655201+0100 ChatBuddy[2094:38562] 8.10.0 - [GoogleUtilities/AppDelegateSwizzler][I-SWZ001014] App Delegate does not conform to UIApplicationDelegate protocol.
entering data snapshot pull
--------------------------
ArdianNuhiji
Nuhijiardian@hotmail.com
ItAoaKj5ZTamf3BHikbdYsHmMhq2
--------------------------
Test
Test@hotmail.com
QkpSyxmV5MfqmhPobdOtQI97cdP2
--------------------------
Test2
Test2@hotmail.com
8xSa6Ff73JMJSq1418rgWtil6442
--------------------------
Test1
Test1@hotmail.com
WQ3f9OnmJTOtbxdEXMEB2j4q3bu2
leaving data snapshot pull
2022-01-05 13:20:32.917846+0100 ChatBuddy[2094:38562] [boringssl] boringssl_metrics_log_metric_block_invoke(151) Failed to log metrics
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

1 Answers1

1

The issue is in with your getFriends method. In your code observeSingleEvent is an asynchronous function, so call completion(friends) only inside that closure, it will fix the issue. Change the method as below.

func getFriends(completion: @escaping ([Friend])-> Void) {
    print("start getFriends")
    self.friends = []
    let ref = Database.database().reference(fromURL: "users")
    
    ref.queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
        print("entering data snapshot pull")
        let snapshotValue = snapshot.value as! [String:[String:[String:AnyObject]]]
        
        for (key, _) in snapshotValue {
            for (_, value) in snapshotValue[key]! {
                var email = ""
                var userName = ""
                var id = ""
                for (key, value) in value {
                    switch key{
                    case "email":
                        email = value as? String ?? ""
                    case "userName":
                        userName = value as? String ?? ""
                    case "id":
                        id = value as? String ?? ""
                    default:
                        print("")
                    }
                }
                print("--------------------------")
                print(userName)
                print(email)
                print(id)
                self.friends.append(Friend(userName: userName, email: email, id: id))
            }
        }
        print("leaving data snapshot pull")
        // CHANGE -----
        completion(friends)
    }
    print("end getFriends")
    
}
Sreekuttan
  • 1,579
  • 13
  • 19