高性能的处理图片

之前曾写过一篇如何通过分类设置纯色图片\带圆角图片等的文章,连接:
http://www.jianshu.com/writer#/notebooks/5359278

上述方法比较简单粗暴,除了在设置圆角图片时避免了离屏渲染的问题,其他性能上并未做优化处理,接下来,继续整理一下对设置图片性能提升方面的处理,这里我们将会借助模拟器为我们提供的两种模式来对项目进行优化:Color Misaligned ImagesColor Blended Layers .

Tableview是日常开发中十分常见的控件,仔细观察会发现,为什么有的app在滚动时,界面非常流畅,而有的app则显得卡顿呢?
先来分析下,在Tableview中往往只有两部分的操作:
1.获取重用Cell
2.根据模型设置数据

通过缓存池和Cell的重用机制,很大程度上缓解了CPU的开销和内存的浪费
而我们需要考虑的就是在获取到重用Cell后,在给Cell设置数据时,减少其对控件的处理来提升性能

Cell中最常见的控件无非就是UIImageView和UILabel,而我们又能够做哪些优化以及系统在设置数据环节还额外的做了哪些处理呢?

首先一点,我们在使用图片时,往往一些图片和视图上的UIImageView尺寸不符,这就导致了图片在设置时,系统要为其做拉伸/缩放处理,如果一个Tableview中需要系统做拉伸/缩放处理的UIImageView很多,就会在一定程度上的出现卡顿的现象

前面都是铺垫,接下来才是这篇文章的重点:如何高性能的设置图片

首先,借助模拟器,我们可以判断出,哪些控件的尺寸是系统做过处理的

模拟器菜单栏中-->Debug-->Color Misaligned Images

options.png

如果勾选后,图像显示为黄色,代表当前图片的大小和使用的ImageView大小不一致,做过拉伸处理

代码演示:

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    imageView.center = self.view.center;
    [self.view addSubview:imageView];
    
    // 直接按照ImageView的尺寸来设置图片
    // 图片的真实尺寸:  640 × 480 pixels
    imageView.image = [UIImage imageNamed:@"路飞.jpg"];

效果图:

misalign_1.png

开启 Color效果图:

misalign_2.png

补充说明:使用模拟器判断缩放时,需要注意模拟器自身的尺寸是否进行过缩放(cmd+1 - 100%...),这里考虑到显示器尺寸,为了让100%显示的模拟器完全显示在屏幕上(如果是5.5寸,100%显示屏幕上显示不全),考虑到呈现效果,使用了6s模拟器

解决方式:

按照UIImageView的尺寸,提前对图片进行拉伸/缩放处理,设置一致后再将图片设置给UIImageView
- (UIImage *)js_imageWithSize:(CGSize)size{
    
    // 开启图形上下文
    UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
    
    // 设置rect
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    
    // 将图片绘制到图形上下文
    [self drawInRect:rect];
    
    // 从图形上下问获取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    // 关闭图形上下文
    UIGraphicsEndImageContext();
    
    // 返回图片
    return image;
    
}

效果图:

misalign_3.png

这样便解决了图片与UIImageView尺寸不一致,系统对齐进行拉伸操作而带来的性能上的浪费

尺寸不一致的问题我们处理完了,设置圆角也是同理

其次,使用颜色的时候,尽可能不要使用带透明度的颜色(不要设置Alpha值)

假设在视图控制器的View中放置一个BlueView和一个GreenView
因视图上产生叠加,默认不设置透明度,处于上层的BlueView就会将叠加部分的GreenView遮挡;
而这时我将处于上层的BlueView设置了透明度,这样GreenView与BlueView叠加部分就会被透出来

在整个屏幕绘制过程中:
1.先将BlueView没有被叠加部分绘制出来
2.其次计算BlueView和BlueView叠加部分区域大小
3.然后再根据BlueView颜色的透明度,叠加了GreenView颜色计算产生的颜色,使用计算的颜色值绘制叠加部分
4.绘制BlueView叠加部分外的区域

blended_1.png

从分析结果来看,如果使用了透明度颜色也会严重影响性能,所以在开发中如果不是刚需,尽量避免使用透明度颜色

既然分析出了需要优化改进的点,那么我们继续使用模拟器自带的功能来对项目进行改进

模拟器菜单栏中-->Debug-->Color Blended Layers
勾选"Color Blended Layers"
这是模拟器为我们提供的一种混合模式
通过混合模式我可以判断出哪些部分进行过透明处理
如果控件部分显示了红色,则表明进行过透明处理,可以对其进行性能上的优化

这里先直接使用上篇文章中设置圆角图片的类方法来演示下效果:

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    imageView.center = self.view.center;
    [self.view addSubview:imageView];

    // 方式一:  设置圆角图片
    UIImage *image = [UIImage imageNamed:@"路飞.jpg"];
    imageView.image = [UIImage js_imageWithOriginalImage:[image js_imageWithSize:CGSizeMake(200, 200)]];
blended_2.png

注意:在UIKit中UILabel的性能是比较差的,但又是不得不用的(也可以自己写一个或者使用其他的开源框架),除了UILabel外,其他的出现混合模式的视图,能处理的我们都应该尽可能的进行优化

代码优化:

// 生成圆角图片(优化后)
- (UIImage *)js_cornerImageWithSize:(CGSize)size{
    
    // 开启图形上下文
    UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
    
    // 设置rect
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    
    // 计算半径
    CGFloat cornerRadius = MIN(size.width, size.height) * 0.5;
    
    // 设置圆形路径并切割
    [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] addClip];
    
    // 将原始图片绘制到图形上下文中
    [self drawInRect:rect];
    
    // 从图形上下获取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    // 关闭图形上下文
    UIGraphicsEndImageContext();
    
    // 返回圆形图片
    return image;
}

效果图:

blended_3.png

不再显示红色

由于开启图形上下文时参数设置为YES(不透明),所以显示有黑边,为了高性能的回去圆形图片,避免设置透明色,我们来传递一个填充色来解决黑边的问题

// 生成圆角图片(优化后)
- (UIImage *)js_cornerImageWithSize:(CGSize)size fillClolor:(UIColor *)fillColor{
    
    // 开启图形上下文
    UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
    
    // 设置rect
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    
    // 设置填充色
    [fillColor set];
    UIRectFill(rect);
    
    // 计算半径
    CGFloat cornerRadius = MIN(size.width, size.height) * 0.5;
    
    // 设置圆形路径并切割
    [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] addClip];
    
    // 将原始图片绘制到图形上下文中
    [self drawInRect:rect];
    
    // 从图形上下获取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    // 关闭图形上下文
    UIGraphicsEndImageContext();
    
    // 返回圆形图片
    return image;
}

效果图:


blended_4.png

这样我们在设置图片时,即没有拉伸,也没有做透明度的混合,当我们在使用Tableview滚动时,就不再会需要对图片执行额外的处理

最后,相对于CPU的处理速度来讲,整个图片处理的过程相当于一个耗时操作,所以我们可以将整个图片过程放到异步执行
// 生成圆角图片(优化后)
- (void)js_cornerImageWithSize:(CGSize)size fillClolor:(UIColor *)fillColor completion:(void(^)(UIImage *img))completion{
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        // 获取开始时间
        CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
        
        // 开启图形上下文
        UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
        
        // 设置rect
        CGRect rect = CGRectMake(0, 0, size.width, size.height);
        
        // 设置填充色
        [fillColor set];
        UIRectFill(rect);
        
        // 计算半径
        CGFloat cornerRadius = MIN(size.width, size.height) * 0.5;
        
        // 设置圆形路径并切割
        [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] addClip];
        
        // 将原始图片绘制到图形上下文中
        [self drawInRect:rect];
        
        // 从图形上下获取图片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        
        // 关闭图形上下文
        UIGraphicsEndImageContext();
        
        // 获取结束时间
        CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
        
        //打印时间
        NSLog(@"%f",end - start);
        
        // 返回圆形图片
        // return image;
        // 返回主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if (completion) {
                completion(image);
            }
        });
        
    });
    
}

这样我们就通过模拟器判断了程序的执行性能并进行了性能上的优化

示例代码:
https://github.com/ShenYj/Demos

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,000评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,745评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,561评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,782评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,798评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,394评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,952评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,852评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,409评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,483评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,615评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,303评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,979评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,470评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,571评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,041评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,630评论 2 359

推荐阅读更多精彩内容

  • 当我们开发iOS应用时,好的性能对我们的App来说是很重要的。你的用户也希望如此,但是如果你的app表现的反应迟钝...
    iOS开发攻城狮阅读 1,529评论 0 14
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,121评论 4 61
  • 郑大主编那打了鸡血似的持续了一周的亢奋之心,被周五那场突如其来的热带暴风雨扑灭。我们从洛溪市新锐传媒大厦出来后,一...
    图革者阅读 927评论 2 45
  • 小径余霜迹,闲阶渐落花。 蹉跎春故事,颠倒梦生涯。 本文已在版权印备案,如需转载请访问版权印。39750653
    念念相续1阅读 849评论 0 2
  • 说得再多,立志再多也是无用的,践行才是我要做的。原本以为能按计划完成每天任务,但事实是过年其间,事情太多,一...
    happny阅读 139评论 0 0