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
相关产品推荐
相关产品推荐

