Swift iOS:如何将TableViewCell子类内的值传递到didSelectRow?
在UITableViewCell内拉取Firebase数据并回传至PlayerController的实现方案
针对你需要在UITableViewCell内直接拉取Firebase数据并回传至PlayerController的场景,我整理了一套可行的实现方案,结合闭包通信和Firebase异步请求的最佳实践来完成:
核心思路
- 在自定义
UITableViewCell中定义回调闭包,用于将拉取到的name和score回传给PlayerController - 在Cell内处理Firebase数据请求,同时做好Cell复用的请求取消逻辑,避免数据错乱
- 在
PlayerController的cellForRowAt方法中绑定闭包,接收回传的数据并更新数据源或UI
具体代码实现
1. 自定义PlayerTableViewCell
import UIKit import FirebaseFirestore class PlayerTableViewCell: UITableViewCell { // 假设你已在xib/storyboard中关联了以下UI控件 @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var scoreLabel: UILabel! @IBOutlet weak var randomPowerLabel: UILabel! // 存储当前Firebase请求的任务令牌,用于复用前取消请求 private var fetchTask: Task<Void, Error>? // 定义回调闭包,传递拉取到的name和score var onDataFetched: ((String, Int) -> Void)? override func prepareForReuse() { super.prepareForReuse() // 复用前取消未完成的请求,防止旧数据覆盖新Cell的UI fetchTask?.cancel() // 重置UI状态 nameLabel.text = "加载中..." scoreLabel.text = "--" } // Cell配置方法:接收玩家标识(比如playerID)和randomPower func configure(withPlayerID playerID: String, randomPower: String) { randomPowerLabel.text = randomPower // 发起Firebase数据请求 fetchTask = Task { do { let db = Firestore.firestore() let docSnapshot = try await db.collection("players").document(playerID).getDocument() guard let playerData = docSnapshot.data(), let name = playerData["name"] as? String, let score = playerData["score"] as? Int else { // 处理数据为空的情况 DispatchQueue.main.async { self.nameLabel.text = "未知玩家" self.scoreLabel.text = "0" self.onDataFetched?("未知玩家", 0) } return } // 主线程更新UI并回传数据 DispatchQueue.main.async { self.nameLabel.text = name self.scoreLabel.text = "\(score)" self.onDataFetched?(name, score) } } catch { // 处理请求错误(比如网络问题、权限不足) DispatchQueue.main.async { self.nameLabel.text = "加载失败" self.scoreLabel.text = "--" } print("Firebase请求失败:\(error.localizedDescription)") } } } }
2. PlayerController中的Cell绑定与数据接收
import UIKit import FirebaseFirestore class PlayerController: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var tableView: UITableView! // 假设你的数据源结构体,存储玩家的基础信息和待填充的name/score struct Player { let playerID: String let randomPower: String var name: String? var score: Int? } var players: [Player] = [] // 初始化时填充playerID和randomPower override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self // 注册自定义Cell(如果用xib的话) tableView.register(UINib(nibName: "PlayerTableViewCell", bundle: nil), forCellReuseIdentifier: "PlayerCell") } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return players.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath) as! PlayerTableViewCell let currentPlayer = players[indexPath.row] // 配置Cell的基础数据 cell.configure(withPlayerID: currentPlayer.playerID, randomPower: currentPlayer.randomPower) // 绑定回调闭包,接收Cell回传的数据 cell.onDataFetched = { [weak self] fetchedName, fetchedScore in guard let self = self else { return } // 更新数据源中的对应玩家信息 self.players[indexPath.row].name = fetchedName self.players[indexPath.row].score = fetchedScore // 如果需要同步更新其他依赖数据源的UI,可以在这里处理 // tableView.reloadRows(at: [indexPath], with: .automatic) } return cell } }
关键注意事项
- 避免循环引用:在
PlayerController的闭包中必须使用[weak self],防止Controller无法被正常释放 - Cell复用处理:在
prepareForReuse中取消未完成的Firebase请求,是解决复用Cell数据错乱的核心 - 主线程更新UI:Firebase请求默认在后台线程执行,更新UI时必须切回主线程
- 错误处理:实际开发中要根据业务需求添加错误提示(比如显示重试按钮),提升用户体验
内容的提问来源于stack exchange,提问作者Lance Samaria
相关产品推荐
相关产品推荐

