Search code examples
swiftfirebasefirebase-realtime-database

no output value of a function


I can't get 3 values out of a function, I get an error message:

Cannot convert value of type '(String, String, String)' to closure result type 'Void'

this is the code:

func readDataUser() -> (uid: String, plan: String, role: String) {
        
        let ref = Database.database().reference()

        let userUid = AuthManager.shared.retrieveUid

        let nodeUser = ref.child(RefDatabase.users.rawValue).child(userUid())

        nodeUser.observeSingleEvent(of: .value) { snapshot in
            
            let uid = snapshot.childSnapshot(forPath: "uid").value as? String ?? "no name"
            let plan = snapshot.childSnapshot(forPath: "plan").value as? String ?? "no name"
            let role = snapshot.childSnapshot(forPath: "role").value as? String ?? "no name"
            
            return (uid, plan, role)
// Cannot convert value of type '(String, String, String)' to closure result type 'Void'
            
        }

// if return (uid, plan, role) i put here it doesn't give the error, but it doesn't print the values, they are empty
        
    }

I would like you to print the values for me:

let dataUser = RealtimeManager.shared.readDataUser()
        print("User data is: \(dataUser.uid) - \(dataUser.plan) - \(dataUser.role)")

Solution

  • As @vadian said, this is an async task. Thus, you cannot treat it as normal sync. I could prefer the new API async rather than completion.

    Firstly, you need to wrap observeSingleEvent completion in withUnsafeContinuation:

    func readDataUser() async -> (uid: String, plan: String, role: String) {
        ...
        return await withUnsafeContinuation { continuation in
            nodeUser.observeSingleEvent(of: .value) { snapshot in
                let uid = snapshot.childSnapshot(forPath: "uid").value as? String ?? "no name"
                let plan = snapshot.childSnapshot(forPath: "plan").value as? String ?? "no name"
                let role = snapshot.childSnapshot(forPath: "role").value as? String ?? "no name"
                continuation.resume(returning: (uid, plan, role))
            }
        }
    }
    

    Then get the value within Task:

    Task {
        let dataUser = await self.readDataUser()
        print("User data is: \(dataUser.uid) - \(dataUser.plan) - \(dataUser.role)")
    }