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:


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

查看所有标签

猜你喜欢:

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

Charlotte's Web

Charlotte's Web

E. B. White / Scholastic / 2004 / USD 0.01

This is the tale of how a little girl named Ferm, with the help of a friendly spider, saved her pig, Wilbur, from the usual fate of nice fat little pigs.一起来看看 《Charlotte's Web》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

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

HSV CMYK互换工具