-3

I need to send data to another TableViewController, but I don't understand why I get an empty array. What am I doing wrong? If I put return in closure at method database, I get an error "Cannot convert value of type '[NewWorkout]' to closure result type 'Void'"

The text below to bypass validation
asdasdasdasdasdasdasdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasdasdasd asdasdasdasdasdasdasdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasd asdasdasdasdasdasdasdasdasd asdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasdasdasdasdas dasdasdasdasdasdasdasdasdasdasdasdasdas

FirebaseHelper singeltone class

import FirebaseAuth
import FirebaseDatabase

class FirebaseHelper {
    static let shared = FirebaseHelper()
    private let database = Database.database(url: "").reference()
    
    private init() {}
    
    func getUserID() -> String {
        return Auth.auth().currentUser!.uid
    }
    
    func saveDataInFirebase(userName: String, setValue: [String:Any]) {
        database.child("\(getUserID())").child("\(userName)").setValue(setValue)
        print("Saved Information")
    }
    
    func fetchDataFromFirebase() -> [NewWorkout]  {
        var workoutList = [NewWorkout]()
        
        database.child("\(getUserID())").observeSingleEvent(of: .value, with: { snapshot in
            guard let value = snapshot.value as? [String:Any] else {return}
            
            for info in value {
                let data = value["\(info.key)"] as? NSDictionary
                
                guard let userName = data?["userName"] as?  String else {return}
                guard let trainingStartDate = data?["trainingStartDate"] as? String else {return}
                guard let trainingTime = data?["trainingTime"] as? String else {return}
                guard let workoutDuration = data?["workoutDuration"] as? String else {return}
                guard let selectedColor = data?["selectedColor"] as? [String:Any] else {return}
                guard let workoutDates = data?["workoutDates"] as? [String] else {return}
                guard let weekDays = data?["weekDays"] as? [String:Any] else {return}
                
                let workout: [NewWorkout] = [NewWorkout(userName: userName,
                                                                                                weekDays: weekDays,
                                                                                                trainingStartDate: trainingStartDate,
                                                                                                workoutDuration: workoutDuration,
                                                                                                wortoutTime: trainingTime,
                                                                                                userColor: [UserColor(red: selectedColor["red"] as? Double ?? 0.0,
                                                                                                                                            green: selectedColor["green"] as? Double ?? 0.0,
                                                                                                                                            blue: selectedColor["blue"] as? Double ?? 0.0)],
                                                                                                workoutDates: workoutDates)]
                workoutList.append(contentsOf: workout)
            }
        })
        
        return workoutList
    }
}

ScheduleTableViewController

import UIKit

class ScheduleTableViewController: UITableViewController {
    
    private var workoutList = [NewWorkout]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        workoutList = FirebaseHelper.shared.fetchDataFromFirebase()
        print(FirebaseHelper.shared.fetchDataFromFirebase()) //print []
    }
    
    // MARK: - Table view data source
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return workoutList.count
    }
    

    override func tableView(_ tableView: UITableView,
                                                    cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ScheduleTableViewCell
        let workout = workoutList[indexPath.row]
        
        cell.timeLabel.text = "\(workout.wortoutTime) (\(workout.workoutDuration))"
        cell.userNameLable.text = workout.userName
        cell.bgView.backgroundColor = UIColor.red.withAlphaComponent(0.28)
        cell.bgLineView.backgroundColor = UIColor.red
        
        return cell
    }
}

My data looks like in Firebase Realtime Database

{
  "BGwLU2FGLmdo987cTvafJUYjeY12": {
    "test": {
      "selectedColor": {
        "blue": 0.4,
        "green": 0.6,
        "red": 0.91
      },
      "trainingStartDate": "24.06.2023, 20:00",
      "trainingTime": "20:00",
      "userName": "test",
      "weekDays": {
        "friday": false,
        "monday": false,
        "saturday": true,
        "sunday": false,
        "thursday": true,
        "tuesday": false,
        "wednesday": true
      },
      "workoutDates": [
        "24.06.2023",
        "28.06.2023",
        "29.06.2023",
        "01.07.2023",
        "05.07.2023",
        "06.07.2023",
        "08.07.2023",
        "12.07.2023",
        "13.07.2023",
        "15.07.2023",
        "19.07.2023",
        "20.07.2023",
        "22.07.2023",
        "26.07.2023",
        "27.07.2023",
        "29.07.2023",
        "02.08.2023",
        "03.08.2023",
        "05.08.2023",
        "09.08.2023",
        "10.08.2023",
        "12.08.2023",
        "16.08.2023",
        "17.08.2023",
        "19.08.2023",
        "23.08.2023",
        "24.08.2023",
        "26.08.2023",
        "30.08.2023",
        "31.08.2023",
        "02.09.2023",
        "06.09.2023",
        "07.09.2023",
        "09.09.2023",
        "13.09.2023",
        "14.09.2023",
        "16.09.2023",
        "20.09.2023",
        "21.09.2023",
        "23.09.2023",
        "27.09.2023",
        "28.09.2023",
        "30.09.2023",
        "04.10.2023",
        "05.10.2023",
        "07.10.2023",
        "11.10.2023",
        "12.10.2023",
        "14.10.2023",
        "18.10.2023",
        "19.10.2023",
        "21.10.2023",
        "25.10.2023",
        "26.10.2023",
        "28.10.2023",
        "01.11.2023",
        "02.11.2023",
        "04.11.2023",
        "08.11.2023",
        "09.11.2023",
        "11.11.2023",
        "15.11.2023",
        "16.11.2023",
        "18.11.2023",
        "22.11.2023",
        "23.11.2023",
        "25.11.2023",
        "29.11.2023",
        "30.11.2023",
        "02.12.2023",
        "06.12.2023",
        "07.12.2023",
        "09.12.2023",
        "13.12.2023",
        "14.12.2023",
        "16.12.2023",
        "20.12.2023",
        "21.12.2023",
        "23.12.2023",
        "27.12.2023",
        "28.12.2023",
        "30.12.2023"
      ],
      "workoutDuration": "180 min"
    },
    "yyyyyy": {
      "selectedColor": {
        "blue": 0.53,
        "green": 0.09,
        "red": 0.51
      },
      "trainingStartDate": "23.06.2023, 1:00",
      "trainingTime": "1:00",
      "userName": "yyyyyy",
      "weekDays": {
        "friday": false,
        "monday": false,
        "saturday": true,
        "sunday": true,
        "thursday": false,
        "tuesday": false,
        "wednesday": true
      },
      "workoutDates": [
        "24.06.2023",
        "25.06.2023",
        "28.06.2023",
        "01.07.2023",
        "02.07.2023",
        "05.07.2023",
        "08.07.2023",
        "09.07.2023",
        "12.07.2023",
        "15.07.2023",
        "16.07.2023",
        "19.07.2023",
        "22.07.2023",
        "23.07.2023",
        "26.07.2023",
        "29.07.2023",
        "30.07.2023",
        "02.08.2023",
        "05.08.2023",
        "06.08.2023",
        "09.08.2023",
        "12.08.2023",
        "13.08.2023",
        "16.08.2023",
        "19.08.2023",
        "20.08.2023",
        "23.08.2023",
        "26.08.2023",
        "27.08.2023",
        "30.08.2023",
        "02.09.2023",
        "03.09.2023",
        "06.09.2023",
        "09.09.2023",
        "10.09.2023",
        "13.09.2023",
        "16.09.2023",
        "17.09.2023",
        "20.09.2023",
        "23.09.2023",
        "24.09.2023",
        "27.09.2023",
        "30.09.2023",
        "01.10.2023",
        "04.10.2023",
        "07.10.2023",
        "08.10.2023",
        "11.10.2023",
        "14.10.2023",
        "15.10.2023",
        "18.10.2023",
        "21.10.2023",
        "22.10.2023",
        "25.10.2023",
        "28.10.2023",
        "29.10.2023",
        "01.11.2023",
        "04.11.2023",
        "05.11.2023",
        "08.11.2023",
        "11.11.2023",
        "12.11.2023",
        "15.11.2023",
        "18.11.2023",
        "19.11.2023",
        "22.11.2023",
        "25.11.2023",
        "26.11.2023",
        "29.11.2023",
        "02.12.2023",
        "03.12.2023",
        "06.12.2023",
        "09.12.2023",
        "10.12.2023",
        "13.12.2023",
        "16.12.2023",
        "17.12.2023",
        "20.12.2023",
        "23.12.2023",
        "24.12.2023",
        "27.12.2023",
        "30.12.2023",
        "31.12.2023"
      ],
      "workoutDuration": "60 min"
    },
  }
}
  • If I add print(workoutList) after workoutList.append(contentsOf: workout), I will see value at workoutList array – Pavel Anpleenko Jun 26 '23 at 18:38
  • Your question is not very clear, especially what you mean by " If I put return in closure at method database" or where in the code you experience the error. – flanker Jun 26 '23 at 19:00
  • Does this answer your question? [Returning data from async call in Swift function](https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function) – HangarRash Jun 26 '23 at 19:21
  • @flanker I mean, if I write return inside a closure I will see an error "Cannot convert value of type '[NewWorkout]' to closure result type 'Void'" – Pavel Anpleenko Jun 27 '23 at 07:50

1 Answers1

0

You note in the comments that if you try to return [NewWorkout]from within the Firebase closure you get an error. This is the expected behaviour as the closure has no return type, i.e. it expects a Void return type, as indicated in error message.

This is evident from the closure's signature: (FIRDataSnapshot) -> Void

Closures are effectively methods, and the same way you wouldn't try to return a value from a method without a return type, you shouldn't from a closure without one.

You also need to keep in mind that your method is (iirc) asynchronous, and therefore attempting to return a value outside of the closure from the closure's call site will almost certainly result in invalid data as it will return before the closure completes. (See link from HangarRash in the comments).

flanker
  • 3,840
  • 1
  • 12
  • 20