背景:
有些时候我们总需要根据数据创建一些视图,当刷新了数据又得移除掉重新创建,这样是不是有些浪费资源了。
那么我们来构想下:
能不能实现像 UITableView 中的 Cell 可以重复利用,但是UITableView 的书写是否啰嗦了点。那我们能不能简化些,如像:
// 1. 懒加载创建一个视图管理适配器
lazy var pinAdapter = EPReusableViewAdapter()
// 2. 移除所有可见视图,再在需要的时候按需创建和显示可用视图
pinAdapter.removeAllVisibleViews()
// 拼团用户头像
if let pinUsers = model.spellDetail?.users {
for (index, user) in pinUsers.enumerated() {
// 3. pinAdapter 就是一个重用视图的管理适配器,按需创建视图,存在就取出来重用
let userImgV = pinAdapter.dequeueReusableView { () -> (UIImageView) in
// 4. 这里的代码只在没有存在可重用的视图才会执行
let userImgV = UIImageView().then {
$0.backgroundColor = .muColor(.background)
$0.layer.cornerRadius = FMPt(15)
$0.layer.masksToBounds = true
}
return userImgV
}
self.addSubview(userImgV)
userImgV.bc_setImageURLString(user.userHead)
userImgV.snp.makeConstraints {
$0.width.height.equalTo(FMPt(30))
$0.centerY.equalTo(titleLab)
$0.left.equalTo(detailLab.snp.right).offset(FMPt(10)+FMPt(24)*CGFloat(index))
}
}
}
这样看起来是不是晴朗些,还是按照正常的代码编写逻辑,只不过往代码中加入了视图管理适配器,让逻辑更加清晰,里面的是怎么管理的就不归我们这业务层的管理了。岂不乐哉!
接下来就看看主代码的实现吧
class EPReusableViewAdapter: NSObject {
private var reusableViews = [UIView]() // 重用队列
public var visibleViews = [UIView]() // 可见队列
/// 获取重用队列中的对象,没有就在block中创建
public func dequeueReusableView<T: UIView>(_ registerViewBlock: (()->(T))) -> T {
guard let view = reusableViews.first else {
// 交给外面来创建
let newView = registerViewBlock()
visibleViews.append(newView)
return newView
}
// 已经去除的要从重用队列中移除
reusableViews.removeFirst()
visibleViews.append(view)
return view as! T
}
/// 移除所有可见视图,重新布局
public func removeAllVisibleViews() {
for view in visibleViews {
reusableViews.append(view)
view.removeFromSuperview()
}
visibleViews.removeAll()
}
}