UIKit

YYKit--YYLabel源码分析

2018-06-14  本文已影响0人  Johnny_Wu

一、YYLabel实现的总体思路

其实YYLabel主要就是为了实现异步绘图,提高性能,为此做了好多东西。

1、使用自定义的Layer,YYAsyncLayer

2、在YYAsyncLayer中实现异步绘图,因为系统默认的绘图都是在主线程执行了的,这里要实现异步绘图,那么就得摈弃掉系统的绘图方法,自己去实现。所以这里得花费很多功夫。所以说,提高性能是要付出很多的。

二、下面开始进入代码分析:

(1)使用自定义的Layer,YYAsyncLayer

在YYLabel中重写了下面的方法:

+ (Class)layerClass {

   return [YYAsyncLayer class];

}

就是修改了View的主Layer层,把YYAsyncLayer的实例作为主Layer层

(2)View与Layer的关系

View其实就是Layer的代理,Layer是View的底层实现,View是Layer的管理类。绘图和坐标等操作都是在Layer中实现的,View只是访问Layer中的相关方法。

(3)系统View的绘图过程:

1、调用setNeedsDisplay

2、调用Layer中的display方法

3、在display中会调用Layer的drawInContext方法

4、在drawInContext中会调用代理方法drawLayer:(CALayer *)layer

inContext:(CGContextRef)ctx,这就进入到View了

5、最后View在代理实现中调用了drawRect方法,这方法就是我们经常用到了那个。

我写了demo验证了上面的过程,结果如下:

(4) YYLabe的绘图过程

在YYAsyncLayer中,我们找到display方法:

- (void)display {

   super.contents = super.contents;

   [self _displayAsync:_displaysAsynchronously];

}

重写了display方法,但没有调用super方法,就是说上面的流程已经被打断了,那么view的系统绘图方法都不会被调用。

通过代理方法newAsyncDisplayTask得到了YYAsyncLayerDisplayTask类实例,再通过调用类实例的block方法直接返回到View中进行操作。作者打断了之前的绘图流程,但这里是通过block进入到UIView中进行绘图操作,这样就可以完全控制绘图过程。

在_displayAsync方法中:

可见,这里是在线程中操作的,先创建了上下文context,然后再调用代理方法:task.display(context, size,isCancelled),所以UIView在代理实现中的绘图操作都是在线程中执行的,这里就实现了异步绘图。

(5) newAsyncDisplayTask的代理实现

上面是得到一些绘图需要的参数,其中最主要的是YYTextLayout对象,里面包含了很多绘图需要的信息。

然后是block display方法:

上面提到这个block实在非主线程执行的,这里执行了真正的绘图操作,绘图操作方法:

[drawLayoutdrawInContext:context size:size point:point view:nil layer:nil debug:debug cancel:isCancelled];中。

具体的绘图还是挺复杂了,看起来有点吃力,以后有机会再研究下。好了,整个YYLabel的实现流程已经分析完成,是不是觉得源码作者很牛逼。作者为了实现异步绘图,花了好多的功夫。

上一篇下一篇

猜你喜欢

热点阅读