内容简介:作者:哈雷哈雷_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 先看一下界面布局:
一个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
然后点击开始监测即可:
下面就是帧率:
这里就可以使用先使用上面的方式做一次改进。
[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
如果感觉这篇文章不错可以点击在看:point_down:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- yii2视图(布局)中各种函数总结报告及使用场景
- iOS小技巧·把子视图控制器的视图添加到父视图控制器
- CouchDB 视图简介及增量更新视图的方法
- c# – 将数据从部分视图传递到其父视图
- Django 基于函数的视图与基于类的视图
- 类视图
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。