UICollectionView滑动流畅性优化
UICollectionView滑动流畅性优化
前言
初始的collection view在滑动时都是十分流畅的,然而因为collection view cell 加载更多的内容时因为主线程耗用太多性能而导致主线程出现堵塞,导致原本流畅的滑动出现卡顿的情况。

collection view加载cell时一般会常用复用池,所以滑动时每要显示一个cell都会调用协议中- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;的方法,而在这方法中除了返回复用池中的cell,程序猿还可以趁机在其中调用cell自定义的读取数据的方法(姑且称之为-(void)loadData:),在本文中即将展示如何将- (void)loadData:中的耗时操作放入NSOperationQueue中并发进行从而不影响collection view的滑动,同时在用户快速滑动中,单个cell的NSOperationQueue中会堆积大量operation的情况,也将在本文中提出应对方法。
NSOperationQueue和NSInvocationOperation
NSOperationQueue将线程操作以队列的形式展现,初始化代码如下:
_queue = ({
NSOperationQueue *q = [[NSOperationQueue alloc]init];
//设置最大并行操作数为1相当于将queue设置为串行线程
q.maxConcurrentOperationCount = 1;
q;
});
每一个operation都是这个队列中的一个元素,而这个元素在满足条件的情况下可以在不用执行就从队列中移除,我们可以利用这种特性来取消其中一些未执行但是不必执行的operation ,关键代码如下:
if (self.operationQueue.operationCount >= 2) {
[self.operationQueue cancelAllOperations];
}
NSInvocationOperation *op = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(operationSelector:)
object:dic];
[self.operationQueue addOperation:op];
其中-(void)cancelAllOperations可以让队列里的所有待执行的operation移除出队列(详情看官方文档),要注意,如果执行此方法时有operation正在执行,那么那些正在执行的operation不会被强行中止并取消。
Canceling the operations does not automatically remove them from the queue or stop those that are currently executing. For operations that are queued and waiting execution, the queue must still attempt to execute the operation before recognizing that it is canceled and moving it to the finished state.——苹果官方开发文档
NSInvocationOperation是NSOperation的子类,它和NSBlockOperation一样都可以作为元素添加到NSOperationQueue中等待执行,最主要的区别在于前者带的是@selector后者带的是block。
异步操作中因视图原因导致程序崩溃时的应对方法
原本高高兴兴把耗时的代码都放到队列中运行时却发现在涉及到视图操作的地方容易出现错乱,甚至是BAD_XXXX之类的崩溃时,就需要检查@selector中是否包含类似addSubview,removeFromSubview之类的傻X操作(每读取一次数据就把view移出来/放进去是什么鬼操作?!View:我来了,我又走了,我来了,我又走了,你打我呀……),遇到这种代码第一想到的是尽量将其移出Operation,最好是将其放到初始化的方法,但是还有些情况是有些视图的属性受到数据的影响,需要等耗时操作结束之后才能确定视图的属性,这个时候就要用到GCD的方法了,如下:
- (void)optimizeOperation:(NSString *)dataStr {
//模拟十分耗时间的操作,注意,这里不能放在main_queue里面执行,否则时间还是消耗在了主线程里面
[NSThread sleepForTimeInterval:0.05];
if ([dataStr isEqualToString:self.dataStr]) {
dispatch_async(dispatch_get_main_queue(), ^{
self.titleLb.text = dataStr;
});
}
}
要注意dispatch_async(dispatch_get_main_queue(), ^{})中不要有耗时的方法,我们到目前为止的铺垫都是为了让占用主线程的滑动操作不要被其他操作堵塞,如果把耗时操作放进去的话就前功尽弃了。

附带demo地址,本文所涉及的思路体现在TextCell.m中:https://github.com/MrYu4/OptimizeCollectionView
可能存在的疑问
- 可是我就是不想用NSInvocationOperation啊,我用NSBlockOperation不行吗?
行
if (self.operationQueue.operationCount >= 2)这个判断语句怎么理解?
队列中如果有两个或两个以上个待出队列的
operation,那么第一个可能是正在执行中的,第二个或者之后都是未执行的(忘了说了,queue设置了最多可并发运行一个operation),这个时候正好是有新的operation等待加入,就说明以往的operation没什么用了,这个时候就可以进行剪枝操作,把operation除去节省性能。
- 接着上个问题,为什么不是>=1呢
[self.operationQueue cancelAllOperations];能立刻去除的是未执行的operation,但正在执行的不会除掉,也就是在cancelAllOperations之前队列内元素个数=1时,就基本上可以确定队列中没有可以除掉的operation了。
求打赏

UICollectionView滑动流畅性优化的更多相关文章
- UITableVIew 滚动流畅性优化
影响UITableViewUITableView滚动的流畅性原因: 1. 在代理方法中做了过多的计算占用了 UI 线程的时间 2.同上 3.Cell 中 view 的组织复杂,比如使用layer并不会 ...
- UITableView 滚动流程性优化
影响 UITableView 滚动的流畅性的原因 1. 在代理方法中做了过多的计算占用了 UI 线程的时间 2.同上 3.Cell 中 view 的组织复杂 关于第一点,首先要明白 tablevi ...
- iOS的流畅性
1优先级别不同:iOS最先响应屏幕 优先级别不同:iOS最先响应屏幕 当我们使用iOS或者是Android手机时,第一步就是滑屏解锁找到相应程序点击进入.而这个时候往往是所有操控开始的第一步骤,iOS ...
- 让页面滑动流畅得飞起的新特性:Passive Event Listeners
版权声明:本文由陈志兴原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/153 来源:腾云阁 https://www.qclo ...
- ios UICollectionView滑动时操作
点开UICollectionViewDelegate,发现有@protocol UICollectionViewDelegate <UIScrollViewDelegate>. 所以只要实 ...
- UIScrollView的delegate方法妙用之让UICollectionView滑动到某个你想要的位置
一个UICollectionView有好多个cell,滑动一下,谁也不知道会停留在哪个cell,滑的快一点,就会多滑一段距离,反之则会滑的比较近,这正是UIScrollview用户体验好的地方. 如果 ...
- Spring配置表友好性优化思路
Spring配置表需要尽量保证对程序员的友好性,一下提供一种优化思路. 中途未保存,心态炸了,只贴图了,fuuuuuuuuuuuuuck 第一种(最烂,最不友好):以Json的格式保存在配置表中,程序 ...
- Android Developers:使ListView滑动流畅
流畅滑动ListView的关键是保持应用程序的主线程(UI线程)从免于繁重处理.确保你的任何硬盘访问,网络访问或者SQL访问在一个单独的线程中.为了测试你的应用个程序的状态,你能启动StrictMod ...
- iOS开发之加载、滑动翻阅大量图片优化解决方案
本文转载至 http://mobile.51cto.com/iphone-413267.htm 今天分享一下私人相册中,读取加载.滑动翻阅大量图片解决方案,我想强调的是,编程思想无关乎平台限制.我要详 ...
- UI的流畅度优化
Android中所有的界面绘制工作都是在UI线程中进行的,提高UI流畅度的最核心根本在于释放UI线程.即:不在主线程中做耗时的操作. 很多人都知道,耗时的操作要放到子线程中去做,比如访问网络,比如读写 ...
随机推荐
- 重回铁王座!时隔5年!Quill 2.0 终于发布啦🎉
你好,我是 Kagol. 2024年4月17日,Quill 2.0 正式发布 最后一个 1.0 版本 1.3.7 发布于 2019年9月9日,时隔4年零7个月. 富文本编辑器拥有非常丰富的使用场景,我 ...
- QT MySQL连接自动断开
参考链接 MySQL链接10天后自动断开解决方案:<https://blog.csdn.net/xiaoxiao133/article/details/123006881 方式一 QT中可以通过 ...
- 在FPGA中何时用组合逻辑或时序逻辑
在设计FPGA时,大多数采用Verilog HDL或者VHDL语言进行设计(本文重点以verilog来做介绍).设计的电路都是利用FPGA内部的LUT和触发器等效出来的电路. 数字逻辑电路分为组合逻辑 ...
- 关于SQL数据库Varchar字符串类型长度设计问题(转载)
为什么要合理的设计数据库字段数据类型的长度?个人观点:一个是降低物理上的存储空间,一个是提高数据库的处理速度,还有一个附带功能是能校验数据是否合法. 现代数据库一般都支持CHAR与VARCHAR字 ...
- 题解:CF1956A Nene's Game
这道题其实挺有意思,多测里面还套了个多测. 思路就是用向量模拟删除过程,具体请看代码里的注释. #include <bits/stdc++.h> using namespace std; ...
- 基于Ubuntu-22.04安装K8s-v1.28.2实验(四)使用域名访问网站应用
安装负载均衡metalb 安装metalb kubectl create namespace metallb-system 配置metalb #kubectl create secret generi ...
- 基于webapi的websocket聊天室(三)
上一篇处理了超长消息的问题.我们的应用到目前为止还是单聊天室,这一篇就要处理的多聊天室的问题. 思路 第一个问题,怎么访问不同聊天室 这个可以采用路由参数来解决.我把路由设计成这样/chat/{roo ...
- Servlet转发与重定向的资源路径问题解析
一. 问题引入 转发和重定向可以说是Servlet中最重要的知识点也不为过,因为它决定着整个向Servlet体系中,执行流程的问题. 转发: request.getRequestDispat ...
- etcd MVCC 存储结构及流程
什么是 MVCC MVCC 是 Multi-Version Concurrency Control 的缩写,即多版本并发控制.它是一种并发控制的方法,用于在数据库系统中实现事务的隔离性.MVCC 是一 ...
- Go 指针逃逸分析
引用 https://my.oschina.net/renhc/blog/2222104