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

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

内容简介:作者:哈雷哈雷_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:


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

查看所有标签

猜你喜欢:

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

软件研发之道

软件研发之道

Jim McCarthy、Michele McCarthy / 赵 俐、石华耀 / 人民邮电出版社 / 2011-8 / 45.00元

Jim McCarlthy等的《软件研发之道 微软开发团队的经验法则》叙述 了微软Visual C++开发团队的故事,通过作者的总结和归纳告诉读者如何 构建一个优秀的软件开发团队,如何在一段时间内成功地交付一个软件。 作为升级版,作者将言简意赅的法则扩展到57条,包括了软件研发及营销 的全部内容,相信每一位项目经理都会对此书爱不释手。 《软件研发之道 微软开......一起来看看 《软件研发之道》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具