RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化

栏目: IT技术 · 发布时间: 6年前

内容简介:作者:哈雷哈雷_Wong为了不影响滑动,第一步,我们一般都是放在子线程中来做,这个不做赘述。

作者:哈雷哈雷_Wong

让UITableView、UICollectionView等延迟加载图片。 下面就拿UITableView来举例说明: UITableView 的 cell 上显示网络图片,一般需要两步,第一步下载网络图片; 第二步,将网络图片设置到UIImageView上。

为了不影响滑动,第一步,我们一般都是放在子线程中来做,这个不做赘述。

第二步,一般是回到主线程去设置。 有了前两篇文章关于Mode的切换,想必你已经知道怎么做了。 就是在为图片视图设置图片时,在主线程设置,并调用

performSelector:withObject:afterDelay:inModes: 方法。最后一个参数,仅设置一个 NSDefaultRunLoopMode

UIImage *downloadedImage = ....;

[self.myImageView performSelector:@selector(setImage:) withObject:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];

当然,即使是读取沙盒或者bundle内的图片,我们也可以运用这一点来改善视图的滑动。但是如果UITableView上的图片都是默认图,似乎也不是很好,你需要自己来权衡了。

有一个非常好的关于设置图片视图的图片,在RunLoop切换Mode时优化的例子:RunLoopWorkDistribution 先看一下界面布局:

RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化

一个Cell里有两个Label,和三个imageView,这里的图片是非常高清的(2034 × 1525),一个界面最多有18张图片。为了表现出卡顿的效果,我先自己实现了一下Cell,主要示例代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

static NSString *identifier = @"cellId";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

if (cell == nil) {

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];

}

for (NSInteger i = 1; i <= 5; i++) {

[[cell.contentView viewWithTag:i] removeFromSuperview];

}

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, 300, 25)];

label.backgroundColor = [UIColor clearColor];

label.textColor = [UIColor redColor];

label.text = [NSString stringWithFormat:@"%zd - Drawing index is top priority", indexPath.row];

label.font = [UIFont boldSystemFontOfSize:13];

label.tag = 1;

[cell.contentView addSubview:label];

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(105, 20, 85, 85)];

imageView.tag = 2;

NSString *path = [[NSBundle mainBundle] pathForResource:@"spaceship" ofType:@"jpg"];

UIImage *image = [UIImage imageWithContentsOfFile:path];

imageView.contentMode = UIViewContentModeScaleAspectFit;

imageView.image = image;

NSLog(@"current:%@",[NSRunLoop currentRunLoop].currentMode);

[cell.contentView addSubview:imageView];

UIImageView *imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(200, 20, 85, 85)];

imageView2.tag = 3;

UIImage *image2 = [UIImage imageWithContentsOfFile:path];

imageView2.contentMode = UIViewContentModeScaleAspectFit;

imageView2.image = image2;

[cell.contentView addSubview:imageView2];

UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectMake(5, 99, 300, 35)];

label2.lineBreakMode = NSLineBreakByWordWrapping;

label2.numberOfLines = 0;

label2.backgroundColor = [UIColor clearColor];

label2.textColor = [UIColor colorWithRed:0 green:100.f/255.f blue:0 alpha:1];

label2.text = [NSString stringWithFormat:@"%zd - Drawing large image is low priority. Should be distributed into different run loop passes.", indexPath.row];

label2.font = [UIFont boldSystemFontOfSize:13];

label2.tag = 4;

UIImageView *imageView3 = [[UIImageView alloc] initWithFrame:CGRectMake(5, 20, 85, 85)];

imageView3.tag = 5;

UIImage *image3 = [UIImage imageWithContentsOfFile:path];

imageView3.contentMode = UIViewContentModeScaleAspectFit;

imageView3.image = image3;

[cell.contentView addSubview:label2];

[cell.contentView addSubview:imageView3];


return cell;

}


然后在滑动的时候,顺便打印出当前的runloopMode,打印结果是:

2016-12-08 10:34:31.450 TestDemo[3202:1791817] current:UITrackingRunLoopMode

2016-12-08 10:34:31.701 TestDemo[3202:1791817] current:UITrackingRunLoopMode

2016-12-08 10:34:32.184 TestDemo[3202:1791817] current:UITrackingRunLoopMode

2016-12-08 10:34:36.317 TestDemo[3202:1791817] current:UITrackingRunLoopMode

2016-12-08 10:34:36.601 TestDemo[3202:1791817] current:UITrackingRunLoopMode

2016-12-08 10:34:37.217 TestDemo[3202:1791817] current:UITrackingRunLoopMode


可以看出,为imageView设置image,是在 UITrackingRunLoopMode 中进行的,如果图片很大,图片解压缩和渲染肯定会很耗时,那么卡顿就是必然的。

查看实时帧率,我们可以在Xcode 中选择 真机调试 ,然后 Product -->Profile-->Core Animation

RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化

然后点击开始监测即可:

RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化

下面就是帧率:

RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化

这里就可以使用先使用上面的方式做一次改进。

[imageView performSelector:@selector(setImage:) withObject:image afterDelay:0 inModes:@[NSDefaultRunLoopMode]];

可以保证在滑动起来顺畅,可是停下来之后,渲染还未完成时,继续滑动就会变的卡顿。在切换到 NSDefaultRunLoopMode 中,一个runloop循环要解压和渲染18张大图,耗时肯定超过50ms(1/60s)。

可以保证在滑动起来顺畅,可是停下来之后,渲染还未完成时,继续滑动就会变的卡顿。在切换到 NSDefaultRunLoopMode 中,一个runloop循环要解压和渲染18张大图,耗时肯定超过50ms(1/60s)。

简单描述一下这种做法:首先创建一个单例,单例中定义了几个数组,用来存要在runloop循环中执行的任务,然后为主线程的runloop添加一个CFRunLoopObserver,当主线程在 NSDefaultRunLoopMode 中执行完任务,即将睡眠前,执行一个单例中保存的一次图片渲染任务。关键代码看  DWURunLoopWorkDistribution 类即可。

总结:

主线程RunLoop切换到 UITrackingRunLoopMode 时,视图有过多的修改

这也就是上面介绍的RunLoop的使用,避免在主线程RunLoop切换到 UITrackingRunLoopMode 时,修改视图。

RunLoopWorkDistribution链接:

https://github.com/diwu/RunLoopWorkDistribution

RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化 如果感觉这篇文章不错可以点击在看:point_down:


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

代码

代码

劳伦斯・莱斯格 / 李旭 / 中信出版社 / 2004-10-1 / 30.00元

劳伦斯·莱斯格的著作《代码》 问世便震动了学界和业界,被人称为“也许是迄今为止互联网领域最重要的书籍”,也被一些学者称为“网络空间法律的圣经”。 《代码》挑战了早期人们对互联网的认识,即技术已经创造了一个自由的环境,因而网络空间无法被规制——也就是说,网络的特性使它押脱了政府的控制。莱斯格提出,事实恰恰相反。 代码的存在证明,网络并不是本制拷贝 ,不可规制的,它并没有什......一起来看看 《代码》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具