Swift弹窗UITableView仅调用一次reloadData()的问题求助
问题分析与解决方案
让我来帮你排查下问题所在,你的代码里有几个关键问题导致了cellForRowAt从未执行的现象:
1. UITableView实例被重新创建,丢失了DataSource和Delegate
你在viewDidLoad中给全局的tblTeams设置了dataSource和delegate,但在ShowTeams方法里又执行了:
tblTeams = UITableView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 180))
这行代码会创建一个全新的UITableView实例,并覆盖原来的全局变量,而这个新实例并没有设置dataSource和delegate!所以弹窗里展示的表格视图根本没有绑定代理方法,自然不会调用cellForRowAt,而你看到的numberOfRowsInSection被调用一次,大概率是旧的、未被展示的表格实例触发的。
解决方法:
要么复用全局的tblTeams实例(推荐),要么给新创建的实例重新设置代理:
方案A:复用全局实例
把ShowTeams里的表格初始化代码改成:
// 不要重新创建实例,直接修改已有实例的frame tblTeams.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 180)
同时把tblTeams.register(...)移到viewDidLoad里,只执行一次:
override func viewDidLoad() { super.viewDidLoad() tblTeams.dataSource = self tblTeams.delegate = self tblTeams.register(UITableViewCell.self, forCellReuseIdentifier: "cellTeams") // 移到这里 RefreshData() }
方案B:给新实例设置代理
如果坚持要重新创建实例,记得添加代理设置:
tblTeams = UITableView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 180)) tblTeams.dataSource = self // 新增 tblTeams.delegate = self // 新增 tblTeams.register(UITableViewCell.self, forCellReuseIdentifier: "cellTeams")
2. 异步数据加载的时机问题
你的RefreshData方法里用循环多次调用Firestore的getDocuments,每次都是异步请求,但你在每个请求完成后就调用reloadData()。这会导致:
- 表格可能在数据还没完全加载完就刷新,显示的行数不准确
- 多次调用
reloadData(),造成不必要的性能消耗
解决方法:
用DispatchGroup等待所有异步请求完成后,统一刷新表格:
func RefreshData(){ let db = Firestore.firestore() guard let uid = Auth.auth().currentUser?.uid else { print("用户未登录") return } dataTeams.removeAll() // 清空现有数据 let dispatchGroup = DispatchGroup() // 用for-in循环替代while,更符合Swift风格 for i in 1...6 { dispatchGroup.enter() // 进入分组 db.collection("teams").whereField("uid\(i)", isEqualTo: uid) .getDocuments() { (querySnapshot, err) in defer { dispatchGroup.leave() } // 不管成功失败都要离开分组 if let err = err { print("获取uid\(i)的团队数据失败:\(err)") } else { for document in querySnapshot!.documents { // 安全解包,避免强制解包崩溃 if let username = document["username"] as? String { self.dataTeams.append(username) } else { print("警告:文档\(document.documentID)缺少username字段") } } } } } // 所有请求完成后,在主线程刷新表格 dispatchGroup.notify(queue: .main) { print("所有团队数据加载完成,共\(self.dataTeams.count)条") self.tblTeams.reloadData() } }
3. 其他优化建议
- 尽量避免强制解包(比如
document["username"] as? String!),改用可选绑定,防止数据格式错误导致崩溃 - 在
ShowTeams方法中,弹窗展示前确保表格已经设置好所有属性(比如rowHeight、separatorColor等) - 如果你的页面只有这一个UITableView,可以去掉代理方法里的
tableView == tblTeams判断,简化代码
按照以上修改后,你的表格应该能正常加载数据并展示cell了。
内容的提问来源于stack exchange,提问作者user10198418
相关产品推荐
相关产品推荐

