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(), ^{})中不要有耗时的方法,我们到目前为止的铺垫都是为了让占用主线程的滑动操作不要被其他操作堵塞,如果把耗时操作放进去的话就前功尽弃了。

很难想象其中每个cell的读取方法中间会有0.05s的耗时方法

附带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滑动流畅性优化的更多相关文章

  1. UITableVIew 滚动流畅性优化

    影响UITableViewUITableView滚动的流畅性原因: 1. 在代理方法中做了过多的计算占用了 UI 线程的时间 2.同上 3.Cell 中 view 的组织复杂,比如使用layer并不会 ...

  2. UITableView 滚动流程性优化

    影响 UITableView 滚动的流畅性的原因 1. 在代理方法中做了过多的计算占用了 UI 线程的时间 2.同上 3.Cell 中 view 的组织复杂   关于第一点,首先要明白 tablevi ...

  3. iOS的流畅性

    1优先级别不同:iOS最先响应屏幕 优先级别不同:iOS最先响应屏幕 当我们使用iOS或者是Android手机时,第一步就是滑屏解锁找到相应程序点击进入.而这个时候往往是所有操控开始的第一步骤,iOS ...

  4. 让页面滑动流畅得飞起的新特性:Passive Event Listeners

    版权声明:本文由陈志兴原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/153 来源:腾云阁 https://www.qclo ...

  5. ios UICollectionView滑动时操作

    点开UICollectionViewDelegate,发现有@protocol UICollectionViewDelegate <UIScrollViewDelegate>. 所以只要实 ...

  6. UIScrollView的delegate方法妙用之让UICollectionView滑动到某个你想要的位置

    一个UICollectionView有好多个cell,滑动一下,谁也不知道会停留在哪个cell,滑的快一点,就会多滑一段距离,反之则会滑的比较近,这正是UIScrollview用户体验好的地方. 如果 ...

  7. Spring配置表友好性优化思路

    Spring配置表需要尽量保证对程序员的友好性,一下提供一种优化思路. 中途未保存,心态炸了,只贴图了,fuuuuuuuuuuuuuck 第一种(最烂,最不友好):以Json的格式保存在配置表中,程序 ...

  8. Android Developers:使ListView滑动流畅

    流畅滑动ListView的关键是保持应用程序的主线程(UI线程)从免于繁重处理.确保你的任何硬盘访问,网络访问或者SQL访问在一个单独的线程中.为了测试你的应用个程序的状态,你能启动StrictMod ...

  9. iOS开发之加载、滑动翻阅大量图片优化解决方案

    本文转载至 http://mobile.51cto.com/iphone-413267.htm 今天分享一下私人相册中,读取加载.滑动翻阅大量图片解决方案,我想强调的是,编程思想无关乎平台限制.我要详 ...

  10. UI的流畅度优化

    Android中所有的界面绘制工作都是在UI线程中进行的,提高UI流畅度的最核心根本在于释放UI线程.即:不在主线程中做耗时的操作. 很多人都知道,耗时的操作要放到子线程中去做,比如访问网络,比如读写 ...

随机推荐

  1. [FAQ] Solidity 实现倒计时 (count down) ?

    思路:一种方式是使用 ethereum-alarm-clock,另一种是合约实现当前过去了多少时间,外部进行不间断调用获得. Any else? Refer:Solidity能倒计时吗 Link:ht ...

  2. 聊聊 dotnet 7 对 bool 与字符串互转的底层性能优化

    本文也叫 跟着 Stephen Toub 大佬学性能优化系列.大家都知道在 .NET 7 有众多的性能优化,其中就包括了对布尔和字符串互转的性能优化.在对布尔和字符串的转换的性能优化上,有着非常巧妙的 ...

  3. mosquitto的安装与使用

      一款实现了消息推送协议 MQTT v3.1 的开源消息代理软件,提供轻量级的,支持可发布/可订阅的的消息推送模式,使设备对设备之间的短消息通信变得简单,比如现在应用广泛的低功耗传感器,手机.嵌入式 ...

  4. Spring6 当中 获取 Bean 的四种方式

    1. Spring6 当中 获取 Bean 的四种方式 @ 目录 1. Spring6 当中 获取 Bean 的四种方式 每博一文案 1.1 第一种方式:通过构造方法获取 Bean 1.2 第二种方式 ...

  5. OpenCompass-书生浦语大模型实战营第二期第7节作业

    书生浦语大模型实战营第二期第7节作业 这一节的作业和第6节作业一样没有特别多好说的,以运行结果为主. 基础作业 使用 OpenCompass 评测 internlm2-chat-1_8b 模型在 C- ...

  6. 《Modern C++ Design》之上篇

    如下内容是在看侯捷老师翻译的<Modern C++ Design>书籍时,整理的code和摘要,用于不断地温故知新. 第一章 1. 运用 Template Template 参数实作 Po ...

  7. blocks (单调栈)

    题目描述 解析 对于这道题,他要求大于k的数进行操作,所以直接让每个数减k,然后用前缀和维护一下与0比较就可以了,因为一段区间和的平 均值大于k的话,那么这就是一个合法区间,即为操作后的这个区间和大于 ...

  8. Java 工程文件的 .gitignore

    以下是一个排查 Java 工程文件的 .gitignore 文件示例: # Java 编译器生成的文件 *.class # Maven 生成的文件夹 target/ # Eclipse 生成的文件夹 ...

  9. Mac远程控制工具有哪些

    适用于Mac的远程控制工具有很多,这里我们给大家列举五个常用软件. 1.Apple Remote Desktop 苹果自带远程桌面正如其名称所承诺的那样.作为 Apple 出品的应用程序,您可以想象它 ...

  10. 2023年的Clion内建立多个子项目(保姆级教程)

    目录 下载插件C/C++ Single File Execution 项目操作 其他操作 下载插件C/C++ Single File Execution 项目操作 1.新建项目-->如图所示操作 ...