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

UIKit下基于Firestore数据添加子视图仅显示单个的问题求助

问题核心原因

你自始至终都在复用同一个newButton实例:

  • 进入网络请求回调之前你就一次性取出了cell.bookButton赋值给newButton变量
  • 循环遍历Firestore返回的多条数据时,你只是修改这同一个按钮的图片、位置属性,再重复调用addSubview
  • UIKit的底层规则是同一个视图实例只能存在于视图层级的一个位置,多次调用addSubview会把这个视图从之前的位置移除,添加到最新的位置,所以最终只会保留最后一次修改后的那一个按钮

修正后代码

func fetchObjects() {
    let index = IndexPath(row: 1, section: 0)
    guard let cell: BookCell = self.backgroundTable.cellForRow(at: index) as? BookCell else { return }
    guard let userID = Auth.auth().currentUser?.uid else { return }
  
    COLLECTION_BOOKS.document(userID).collection("collections").getDocuments { (snapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            return
        } 
        guard let documents = snapshot?.documents else { return }
        for document in documents {
            // 每次遍历一条数据就新建一个按钮实例,不要复用单个固定按钮
            let newButton = UIButton(type: .custom)
            // 此处的尺寸可替换为你原项目中bookButton的实际尺寸
            newButton.frame.size = CGSize(width: 80, height: 80)
            
            let imageURL = document.get("imageURL") as! String
            let xLocation = document.get("xLocation") as! Double
            let yLocation = document.get("yLocation") as! Double
               
            let buttonPhotoString = imageURL
            if let url = URL(string: buttonPhotoString) {
                // 同步网络请求移到子线程,避免阻塞主线程导致界面卡顿
                DispatchQueue.global().async {
                    if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
                        DispatchQueue.main.async {
                            newButton.setImage(image, for: .normal)
                            newButton.frame.origin.x = xLocation
                            newButton.frame.origin.y = yLocation
                            cell.canvasView.addSubview(newButton)
                        }
                    } else {
                        print("Unable to get image data")
                    }
                }
            } else {
                print("Unable to process url string")
            }
        }
    }
}

额外优化建议

  • 原代码中的Data(contentsOf: url)是同步网络请求,生产环境更推荐使用成熟的图片加载框架处理,减少自行维护的逻辑复杂度
  • 强制类型转换as!存在崩溃风险,建议替换为as?的可选绑定写法,避免后台返回数据格式异常时APP闪退
  • 如果后续有删除、批量刷新按钮的需求,建议给每个新建的按钮设置唯一tag,或者将按钮实例存入数组统一管理,方便后续操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:09:02