Swift中Firebase数据传至TableViewController时数组为空问题排查
Firebase异步数据获取空数组问题解决
问题根源
Firebase Realtime Database的数据获取是异步操作,你当前的fetchDataFromFirebase函数是同步返回数组,函数会在Firebase请求完成前就返回初始化的空数组,所以拿到的结果始终是空的。另外,闭包的返回类型是Void,不能在闭包内返回[NewWorkout]类型的值,这就是你遇到类型转换错误的原因。
修改后的FirebaseHelper代码
将同步返回改为异步回调方式,用completion handler传递数据:
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") } // 改为带completion的异步方法 func fetchDataFromFirebase(completion: @escaping ([NewWorkout]) -> Void) { var workoutList = [NewWorkout]() database.child("\(getUserID())").observeSingleEvent(of: .value, with: { snapshot in guard let value = snapshot.value as? [String:Any] else { completion(workoutList) return } for (_, infoValue) in value { guard let data = infoValue as? NSDictionary else { continue } guard let userName = data["userName"] as? String else { continue } guard let trainingStartDate = data["trainingStartDate"] as? String else { continue } guard let trainingTime = data["trainingTime"] as? String else { continue } guard let workoutDuration = data["workoutDuration"] as? String else { continue } guard let selectedColor = data["selectedColor"] as? [String:Double] else { continue } guard let workoutDates = data["workoutDates"] as? [String] else { continue } guard let weekDays = data["weekDays"] as? [String:Bool] else { continue } let userColor = UserColor(red: selectedColor["red"] ?? 0.0, green: selectedColor["green"] ?? 0.0, blue: selectedColor["blue"] ?? 0.0) let workout = NewWorkout(userName: userName, weekDays: weekDays, trainingStartDate: trainingStartDate, workoutDuration: workoutDuration, wortoutTime: trainingTime, userColor: [userColor], workoutDates: workoutDates) workoutList.append(workout) } // 数据解析完成后通过completion返回 completion(workoutList) }) } }
修改后的ScheduleTableViewController代码
在回调中更新数据并刷新表格:
import UIKit class ScheduleTableViewController: UITableViewController { private var workoutList = [NewWorkout]() override func viewDidLoad() { super.viewDidLoad() // 调用异步方法,在completion中更新数据 FirebaseHelper.shared.fetchDataFromFirebase { [weak self] workouts in guard let self = self else { return } self.workoutList = workouts print(workouts) // 现在能打印出正确的数据 // 主线程刷新表格 DispatchQueue.main.async { self.tableView.reloadData() } } } // 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 // 可以用解析后的userColor设置背景色 let color = workout.userColor.first cell.bgView.backgroundColor = UIColor(red: color?.red ?? 0.91, green: color?.green ?? 0.6, blue: color?.blue ?? 0.4, alpha: 0.28) cell.bgLineView.backgroundColor = UIColor(red: color?.red ?? 0.91, green: color?.green ?? 0.6, blue: color?.blue ?? 0.4, alpha: 1.0) return cell } }
额外优化点
- 原循环中
value["\(info.key)"]替换为info.value,更高效简洁。 - 解析
selectedColor时直接指定[String:Double]类型,避免后续强制转换Double。 - 更新UI操作必须放在主线程,用
DispatchQueue.main.async包裹表格刷新。 - 使用
[weak self]避免循环引用。
内容的提问来源于stack exchange,提问作者Pavel Anpleenko
相关产品推荐
相关产品推荐

