Swift3下UITableView滚动时动态添加的UIImageView错乱问题求助
嘿,这个问题我太熟了——UITableView的cell复用机制就是搞事情的元凶!当你滚动列表时,系统会把滑出屏幕的cell回收进复用池,等需要时再拿出来重新利用。如果你的UIImageView是每次在cellForRowAt里动态添加到自定义视图的,却没在复用的时候做清理或重置,自然会出现重复添加、显示错乱的情况。下面给你Swift 3环境下的靠谱解决方案:
解决方案(Swift 3)
1. 最优方案:把UIImageView作为自定义Cell的固定属性
别每次创建cell都新生成UIImageView,提前把它作为自定义Cell的成员变量,在Cell初始化时就添加到视图层级里,只做一次。这样复用的时候就不会重复添加,还能保证性能。
示例自定义Cell代码:
class CustomTableViewCell: UITableViewCell { // 把UIImageView设为Cell的成员变量,提前初始化 let customImageView: UIImageView = { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.clipsToBounds = true iv.translatesAutoresizingMaskIntoConstraints = false return iv }() override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) // 初始化时把ImageView添加到contentView,只执行一次 contentView.addSubview(customImageView) // 给ImageView加约束(示例,根据你的布局调整) NSLayoutConstraint.activate([ customImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), customImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), customImageView.widthAnchor.constraint(equalToConstant: 40), customImageView.heightAnchor.constraint(equalToConstant: 40) ]) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 复用前重置内容,避免残留旧数据 override func prepareForReuse() { super.prepareForReuse() customImageView.image = nil // 清空旧图片 // 如果有其他状态(比如隐藏/显示、 tintColor)需要重置,也在这里处理 } }
2. 在数据源方法里直接赋值
之后在TableView的cellForRowAt方法里,直接给Cell的ImageView赋值就行,不用再创建新视图:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell // 根据当前indexPath获取对应的数据 let item = yourDataSourceArray[indexPath.row] // 给ImageView设置图片(本地图或网络图都可以) cell.customImageView.image = UIImage(named: item.imageName) // 如果是网络图片,推荐用SDWebImage这类库异步加载,避免卡顿 return cell }
3. 特殊情况:必须动态添加视图(不推荐)
如果因为业务限制必须动态添加UIImageView,那一定要在prepareForReuse里把之前添加的视图清理掉,避免复用残留:
override func prepareForReuse() { super.prepareForReuse() // 方式1:移除所有UIImageView(如果Cell里只有这一个ImageView的话) for subview in contentView.subviews { if subview is UIImageView { subview.removeFromSuperview() } } // 方式2:给ImageView设置唯一tag,精准移除(更安全) // if let oldImageView = contentView.viewWithTag(1001) { // oldImageView.removeFromSuperview() // } }
然后再在cellForRowAt里重新创建添加,但这种方式性能不如固定属性的方案,能不用就不用。
核心原因复盘
UITableView的cell复用机制是关键:滑出屏幕的Cell不会被销毁,而是被放进复用池,下次需要时直接取出复用。如果之前的Cell里已经有UIImageView,复用的时候不清理,新的内容叠加上去,就会出现显示错乱、重复显示的问题。所以解决的核心就是复用前重置状态,避免重复添加视图。
内容的提问来源于stack exchange,提问作者Vikram Surjan
相关产品推荐
相关产品推荐

