You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITableView重复调用reloadData致能耗过高问题求助

解决UITableView无限重载与卡顿问题的方案

兄弟,你这问题的根源太明显了——你在cellForRowAt里调用reloadData(),直接导致了无限循环:每次tableView刷新都会重新创建所有cell,每个cell创建时又触发刷新,循环往复,不卡顿、不耗电才怪!

咱们换个思路,正确的做法是只在数据准备完成后调用一次刷新,而不是在cell创建时瞎折腾。下面一步步给你改:

1. 先砍掉cell里的致命代码

把cellForRowAt里的DispatchQueue.main.async { reloadData() }删掉,这是无限循环的罪魁祸首。修改后的cell方法应该是这样的:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // 推荐提前注册cell,这里先兼容你的写法
    var cell = charitiesSupportedTable.dequeueReusableCell(withIdentifier: "SupportedCell") 
    if cell == nil {
        cell = UITableViewCell(style: .subtitle, reuseIdentifier: "abc")
    }
    // 因为numberOfRows会返回数组长度,所以不用判断越界
    let charityName = charOfPrevPostsArray[indexPath.row]
    let moneyRaised = moneyRaisedOfPrevPostsArray[indexPath.row]
    cell?.textLabel?.text = charityName
    cell?.detailTextLabel?.text = moneyRaised
    return cell!
}

2. 在数据加载完成后才刷新tableView

你的Firebase数据加载是异步的,之前数据回来后你只更新了数组,但没通知tableView刷新,所以一开始cell里没内容。现在要在数据处理完后,在主线程触发刷新:

override func viewDidLoad() {
    super.viewDidLoad()
    guard let userEmail = Auth.auth().currentUser?.email else {
        // 处理用户未登录的情况,避免崩溃
        return
    }
    var email1 = userEmail.replacingOccurrences(of: "@", with: "", options: .literal)
    email1 = email1.replacingOccurrences(of: ".", with: "", options: .literal)
    
    charitiesSupportedTable.delegate = self
    charitiesSupportedTable.dataSource = self
    charitiesSupportedTable.isScrollEnabled = false
    
    // 加载用户过往帖子数据
    let postsRef = Database.database().reference().child("Posts")
    let userPostsRef = postsRef.queryOrdered(byChild: "user").queryEqual(toValue: email1)
    userPostsRef.observe(.value, with: { [weak self] snapshot in
        guard let self = self else { return }
        // 每次数据更新先清空数组,防止重复添加
        self.charOfPrevPostsArray.removeAll()
        self.moneyRaisedOfPrevPostsArray.removeAll()
        
        for child in snapshot.children {
            let snap = child as! DataSnapshot
            guard let valueAsDict = snap.value as? [String: Any],
                  let charity = valueAsDict["charity"] as? String,
                  let viewCountStr = valueAsDict["viewCount"] as? String,
                  let viewCount = Double(viewCountStr) else {
                // 跳过格式错误的数据,避免崩溃
                continue
            }
            let moneyRaised = viewCount * 0.006
            self.charOfPrevPostsArray.append(charity)
            self.moneyRaisedOfPrevPostsArray.append(String(moneyRaised))
        }
        // 反转数组
        self.charOfPrevPostsArray.reverse()
        self.moneyRaisedOfPrevPostsArray.reverse()
        
        // 数据准备好后,在主线程刷新tableView(UI操作必须在主线程)
        DispatchQueue.main.async {
            self.charitiesSupportedTable.reloadData()
        }
    })
    
    // 加载总筹款数据
    let totalMoneyRef = Database.database().reference().child("UsersViews").child(email1).child("totalMoneyRaised")
    totalMoneyRef.observe(.value, with: { [weak self] snapshot in
        guard let self = self, let totalMoney = snapshot.value as? Double else { return }
        DispatchQueue.main.async {
            self.totalMoneyLabel.text = String(format: "$%.02f", totalMoney)
        }
    })
    
    // 加载支持的慈善机构数量(如果行数依赖这个值)
    let charitiesSupportedRef = Database.database().reference().child("UsersViews").child(email1).child("charitiesSupported")
    charitiesSupportedRef.observe(.value, with: { [weak self] snapshot in
        guard let self = self, let myDictionary = snapshot.value as? [String: Any] else { return }
        self.myCharities.removeAll()
        for value in myDictionary.values {
            if let charity = value as? String {
                self.myCharities.append(charity)
            }
        }
        self.charitiesCount = self.myCharities.count
        // 如果行数依赖这个count,这里也要触发刷新
        DispatchQueue.main.async {
            self.charitiesSupportedTable.reloadData()
        }
    })
}

3. 修正行数计算逻辑

确保numberOfRowsInSection返回的是你实际要显示的数组长度,而不是模糊的charitiesCount + 2:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // 如果你要显示过往帖子的数据,直接返回数组长度
    return charOfPrevPostsArray.count
    // 如果确实需要返回charitiesCount + 2,确保上面的慈善机构数量更新后会触发刷新
    // return charitiesCount + 2
}

额外优化建议

  • 提前注册cell:在viewDidLoad里添加charitiesSupportedTable.register(UITableViewCell.self, forCellReuseIdentifier: "SupportedCell"),这样就不用判断cell是否为nil了,复用更高效。
  • 避免实时监听(如果不需要):如果你的数据不需要实时更新,把observe(.value)换成observeSingleEvent(of: .value),减少不必要的回调和能耗。
  • 防止循环引用:用[weak self]捕获self,避免Firebase回调导致内存泄漏。

内容的提问来源于stack exchange,提问作者Nate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:09:16