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

基于Firebase的Todo App:Collection View数据显示与数量异常问题

问题分析与修复方案

核心问题拆解

  1. Firebase数据获取逻辑错误:
    • 每次快照触发时未清空任务数组,且在遍历文档的循环内多次调用completion和刷新视图,导致数据源被重复填充,出现单元格数量异常。
    • 函数参数uid未被使用,冗余获取currentUser.uid,逻辑混乱。
  2. Collection View Cell配置错误:
    • 使用静态类属性TasksViewCell.textLabel设置文本,而非当前cell实例的属性,导致文本无法正确显示,且单元格复用会出现异常。
  3. 视图刷新时机错误:
    • 在遍历文档的循环内多次调用reloadData(),导致视图被重复刷新,引发显示混乱。

具体修复代码

1. 修复Firebase数据获取函数

func fetchTasks(uid: String, completion: @escaping([Task])-> Void) {
    Firestore.firestore().collection("tasks")
        .document(uid)
        .collection("ongoing_tasks")
        .order(by: "timestamp")
        .addSnapshotListener { snapshot, error in
            if let err = error {
                print(err)
                return
            }
            
            guard let snapShotDocuments = snapshot?.documents else {
                completion([])
                return
            }
            
            // 每次快照更新时先清空数组,避免重复添加
            var tasks = [Task]()
            for doc in snapShotDocuments {
                let data = doc.data()
                tasks.append(Task(data: data))
            }
            // 遍历完成后一次性返回完整任务列表
            completion(tasks)
        }
}

2. 修复数据源更新与视图刷新逻辑

private func fetchTasks() {
    guard let uid = self.user?.uid else { return }
    fetchTasks(uid: uid) { fetchedTasks in
        // 改用实例属性存储数据源(替代静态属性,避免全局状态混乱)
        self.tasks = fetchedTasks
        // 数据源更新后统一刷新Collection View
        self.collectionView.reloadData()
    }
}

// TasksViewController内修改数据源为实例属性
var tasks = [Task]()

3. 修复Collection View Cell配置

class TasksViewCell: UICollectionViewCell {
    // 定义实例化的文本标签(替代静态类属性)
    let textLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 16)
        return label
    }()
    
    var task: Task? {
        didSet {
            configure()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(textLabel)
        // 添加约束确保标签正确布局
        NSLayoutConstraint.activate([
            textLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
            textLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
            textLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func configure() {
        guard let task = self.task else { return }
        // 使用当前cell实例的textLabel设置文本
        self.textLabel.text = task.text
    }
}

4. 优化Collection View代理方法

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return tasks.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! TasksViewCell
    cell.task = tasks[indexPath.row]
    return cell
}

5. 优化任务保存函数(可选)

@objc func addTaskButtonClicked() {
    guard let text = NewTaskViewController.textView.text, !text.isEmpty else {
        makeAlert(titleInput: "Error", messageInput: "Please write your task.")
        return
    }
    
    guard let currentUid = Auth.auth().currentUser?.uid else { return }
    let taskId = UUID().uuidString
    let data: [String: Any] = [
        "text": text,
        "timestamp": Timestamp(date: Date()),
        "taskId": taskId
    ]
    
    Firestore.firestore().collection("tasks")
        .document(currentUid)
        .collection("ongoing_tasks")
        .document(taskId)
        .setData(data) { error in
            if let err = error {
                print("保存任务失败:\(err)")
            } else {
                NewTaskViewController.textView.text = ""
            }
        }
}

修复关键点总结

  • 每次Firebase快照更新时,先清空任务数组,遍历完成后一次性更新数据源并刷新视图,避免重复添加。
  • Cell配置使用实例属性而非静态类属性,确保每个单元格的文本与任务正确绑定。
  • 改用实例属性存储数据源,减少全局状态带来的逻辑混乱。
  • 清理冗余代码,确保函数参数被正确使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:36:00