简述
最近项目有一个 单列表页面
计划要修改成 多列表页面
, 虽然目前还是单列表, 但是既然有这样的计划, 就自行先实现了.
一开始 单列表
使用的是 UITableView
全程流畅滚动. 但是换成 UICollectionView
的 单列表
之后, 列表就开始出现了滑动 掉帧
的情况.
所有逻辑都是一模一样的, 仅仅是换了一个列表控件, 这个情况还是蛮奇怪的, 只好查找一下是不是什么被地方忽略了.
网上一大堆 UITableView
和 UICollectionView
滚动视图的优化文章, 也看了不少, 但是这个列表真的是简单到不能再简单了 (一个占满了 Cell 的 UIImageView 而已
), 之前写那么多这样的列表也没出现 掉帧
的情况, 只好一一排查.
排查问题
优化方面的问题有简单有复杂, 先从简单的方面做起:
1.是否主线程处理大量数据造成了卡顿?
大批量的数据处理都在 子线程
进行, cell
也只是在 setter
里面进行简单的 值展示
赋值和一个 图片文件读取
以及 UIImage
对象的赋值.
注释掉 文件读取
代码之后卡顿掉帧的情况依旧存在.
注释掉整个 setter
方法之后卡顿依旧.
2.是否有多余的无需实现的代理方法?
因为列表高度是根据内容变化的, 因此代理方法仅仅实现了 UICollectionViewDelegateFlowLayout
的
1
2
3
4
5
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// 宽度: collectionView 的宽度
// 高度: 为了适应不同屏幕, 高度 * 宽度比系数
return CGSizeMake(CGRectGetWidth(collectionView.bounds), height * scale);
}
其他需要计算的代理方法均未实现.
针对此处优化, 就对 每行的高度
做了 缓存
, 问题也未得到解决.
3.检查一下 Cell 内部 UI 约束的代码
就这么多, 的确是简单到不能再简单了.
1
2
3
4
5
6
7
8
#pragma mark - UI
- (void)setupUI {
[self.contentView addSubview:self.imageView];
[_imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsZero);
}];
}
既然要优化, 此处 Masonry
的约束也不是必须的, 这样写也是因为布局简单, 认为不太会造成太严重的性能上的问题.
把布局的代码改成这样:
1
2
3
- (void)layoutSubviews {
_scrollView.frame = self.bounds;
}
跑起来看看, 不卡了…
真的不敢相信…
就这么一个 约束
就能造成这么严重的性能问题???
总结
这次的问题从发现到解决花费了将近 3
个小时, 仅仅一个看似没有任何问题的 自动布局
造成的很严重的问题.
自动布局
的 性能问题
对于做过一段时间 iOS 开发的来讲, 都是常识. 但是自认为:
Cell
布局简单, 自动布局的约束造成的性能问题微乎其微.
因此从一开始就没从这方面来考虑这个问题, 导致花了半个下午的时间来解决这么一个看似简单的 BUG
.
看似一个简单的 约束
却让整个列表产生了严重的性能问题.
就当是偷懒和安于习惯的惩罚吧, 吸取教训才是最重要的.