V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
adow
V2EX  ›  iDev

关于CALayer 的速度

  •  
  •   adow ·
    adow · 2012-05-09 00:02:53 +08:00 · 9370 次点击
    这是一个创建于 4367 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近在做的一个项目中,需要在UITableViewCell中的UIImageView中显示头像,他们是32*32的正方形小图片,为了实现圆角的效果,我给这个UIImageView设置了CALayer的几个相关属性:

    self.imgAvator.layer.cornerRadius=3.0;
    self.imgAvator.layer.borderWidth=1.0;
    self.imgAvator.layer.borderColor=[UIColor colorWithRed:0 green:0 blue:0 alpha:0.05].CGColor;
    self.imgAvator.clipsToBounds=YES;

    当然他很好的实现了圆角的效果;

    可是在实际运行中,我发现这个UITableView的滚动速度不是很理想,在排除了其他我感觉可能引起的问题之后,我去掉了这个layer的代码,感觉速度有明显的提升了。

    然后,我没有使用layer来实现圆角,而是在获取UIImage后直接做了处理剪裁出圆角图片,这时速度依然比使用layer的明显要快。

    所以我想问的是,使用CALayer的绘图会影响UI的速度吗,有啥优化的办法没有呢?
    15 条回复    1970-01-01 08:00:00 +08:00
    Sai
        1
    Sai  
       2012-05-09 00:17:17 +08:00   ❤️ 1
    Try layer.shouldRasterize = YES;
    txx
        2
    txx  
       2012-05-09 05:24:56 +08:00   ❤️ 1
    我一直觉得coreanimation的效率非常不错

    lz您不会是cell没写好吧。。
    adow
        3
    adow  
    OP
       2012-05-09 11:06:17 +08:00
    @Sai 我用了layer.shouldResterize=YES,速度好像没有明显的改善啊,所以现在还是直接在UIImage上处理之后比较流畅;
    @txx 我也怀疑cell哪里写的有问题,我检查了一些地方,cell reuse 是正常工作的,table的数据现在是从本地的缓存里加载的,我去掉了头像以外所有的数据显示,没有明显的改善,只有去掉layer的几句代码才让我突然感受到流畅不少了,所以我才怀疑这个问题。
    dongsheng
        4
    dongsheng  
       2012-05-09 11:13:41 +08:00   ❤️ 1
    有没有试试直接把图片直接画到cell的CALayer上?额外用UIImageView肯定要消耗更多资源。
    adow
        5
    adow  
    OP
       2012-05-09 11:15:09 +08:00
    google 了一下CALayer,看到了 @livid 的这个http://picky.olivida.com/calayer-and-ipad-apps-performance

    > 每一个 UIView 对象实例都包含一个 CALayer 实例,可以通过 [myView layer] 的方式访问到。而 CALayer 又提供了非常多的邪恶功能,比如修改一个 view 的圆角程度,甚至给它加阴影。这些方法都非常好用。但是代价就是程序的 framerate 就会大受影响,尤其是执行诸如 presentModalViewController 这样全屏幕豪华操作时。

    结论是:要用 CALayer 可以,但是在写到屏幕上之前一定要先将这个 layer 的内容变成一坨简单的 bitmap,否则就等着看幻灯片吧。
    jesse0628
        6
    jesse0628  
       2012-05-09 11:43:13 +08:00   ❤️ 1
    跟楼主体会完全一样,我一直找不到原因,为什么我的添加到scroll view里面的东西会滚起来那么卡,原因大概还是我里面用了很多CALayer圆角的东西,也做了一些CALayer比如绘制什么的操作。但是应该最大的问题是圆角引起的。
    senopanas
        7
    senopanas  
       2012-05-09 11:45:14 +08:00   ❤️ 1
    clipsToBounds=YES实际上还多了一个step跳转到masksToBounds=YES,效果当然都一样:
    -(BOOL)[UIView(Rendering) clipsToBounds]
    +0 3091938a 55 pushl %ebp
    +1 3091938b 89e5 movl %esp,%ebp
    +3 3091938d e800000000 calll 0x30919392
    +8 30919392 59 popl %ecx
    +9 30919393 8b4508 movl 0x08(%ebp),%eax
    +12 30919396 8b5004 movl 0x04(%eax),%edx (CALayer)_layer
    +15 30919399 8b8186cb1301 movl 0x0113cb86(%ecx),%eax masksToBounds
    +21 3091939f 89450c movl %eax,0x0c(%ebp)
    +24 309193a2 895508 movl %edx,0x08(%ebp)
    +27 309193a5 c9 leave
    +28 309193a6 e92e211801 jmpl 0x31a9b4d9

    不过至少可以省一步,shouldResterize效果不大但是有效果。一般来说在cell上添加一个CAlayer的圆角并且masksToBounds也不会降低多少performance,你的头像图片是lazy loading吗?
    mr_pppoe
        8
    mr_pppoe  
       2012-05-09 11:59:42 +08:00   ❤️ 1
    隐约记得有一段WWDC的视频讨论了类似的问题
    adow
        9
    adow  
    OP
       2012-05-09 12:01:02 +08:00
    @senopanas 头像是异步http下载的,我现在是下载完后处理成圆角的UIImage后赋值到imgAvator.image上
    adow
        10
    adow  
    OP
       2012-05-09 12:04:07 +08:00
    哦对了,实际运行中,因为头像部分的http请求做了缓存,所以大部分是本地读取的文件,跳过http请求的
    elden
        11
    elden  
       2012-05-09 12:30:58 +08:00   ❤️ 1
    直接设置cornerRadius会影响滚动的流畅性。如果cell不使用复杂背景,那可以在头像上覆盖一层空心的圆角图片。
    ultragtx
        12
    ultragtx  
       2012-05-09 12:45:08 +08:00   ❤️ 3
    CALayer直接setCornerRadius会发生offscreen rendering,简单地说就是在屏幕外渲染一遍,接着再渲染到屏幕上(涉及到多开一个屏幕外buffer,屏幕内buffer和屏幕外buffer来回切换等问题),CoreAnimation是逐帧渲染的,所以scroll的时候每帧都进行这个操作,结果就很慢,解决方法一般就是先把圆角图片画出来。
    一楼Sai那个方法就是缓存offscreen render,这样就不用每帧都渲染一遍,但是要求layer的内容是不变的,如果有变化还是要慢,不过你这个情况应该符合。

    具体参考WWDC 2011 Session 121 这个讲的特别细
    adow
        13
    adow  
    OP
       2012-05-09 12:52:27 +08:00
    感谢大家的讨论,我之前一直都不知道这些。
    keakon
        14
    keakon  
       2012-05-11 20:55:36 +08:00   ❤️ 1
    最好不要用 UIImageView 和 CALayer,比直接显示肯定要慢的。另外可以用预渲染:
    http://www.keakon.net/article/96200
    http://www.keakon.net/article/98200
    hydyy
        15
    hydyy  
       2012-12-07 21:56:10 +08:00
    哈喽~ 楼主您解决这个问题了嘛? 我也遇到了~~哈哈阿红
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4966 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:50 · PVG 17:50 · LAX 02:50 · JFK 05:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.