视觉-iOS中图片文件渲染到屏幕的过程

2020-07-21  本文已影响0人  Johnny_Z

一、图片到屏幕view过程

1、数据处理过程


图片数据

2、硬件协同处理细节

硬件处理

二、图片加载到渲染的工作流程

1、从文件加载图片数据 可以使用类方法+imageNamed: ,此时我们得到图片原始数据
2、将UIImage 赋值给UIImageView
3、CATransaction捕获到UIImageView图层树的变化
4、主线程runloop提交 CATransaction,开始进行解码和图像渲染,这里会涉及到

5、渲染

注意:
1、图片只有在确认需要显示时,CPU才对其进行解压;+imageName:or+imageNamed:inBundle:compatibleWithTraitCollection:加载的图片,系统会对其自动缓存,以便下次使用,但如果用+imageWithContentsOfFile:-initWithContentsOfFile:系统会每次都从disk加载,对应的都需要解压;imageWithData直接读取原始数据,如果非GPU能直接处理的数据(位图或矢量图)是需要解压的;
2、解码是一个比较消耗CPU的操作,且默认在主线程,当界面上一次性确定显示多张图片时表现得尤为突出,此时一般的做法可以将解码操作放到异步线程去完成,解码后再用来展示

三、探究YYImage

1、YYImage 类结构分析

2、分析YYAnimatedImageView

- (instancetype)init {
    self = [super init];
    _runloopMode = NSRunLoopCommonModes;
    _autoPlayAnimatedImage = YES;
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    _runloopMode = NSRunLoopCommonModes;
    _autoPlayAnimatedImage = YES;
    return self;
}

- (instancetype)initWithImage:(UIImage *)image {
    self = [super init];
    _runloopMode = NSRunLoopCommonModes;
    _autoPlayAnimatedImage = YES;
    self.frame = (CGRect) {CGPointZero, image.size };
    self.image = image;
    return self;
}

初始化中指定了runloopModeNSRunLoopCommonModes

  [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:_runloopMode];

_runloopMode 指定到了 CADisplayLinklink中,不断地替换_curFrame用来跟新layer里面显示的图片frame,将link的指定成NSRunLoopCommonModes保证了在拖动滚动视图时动画还能继续。

//创建_requestQueue 设置最大并发量1
_requestQueue = [[NSOperationQueue alloc] init];
_requestQueue.maxConcurrentOperationCount = 1;
//解码操作加入_requestQueue
_YYAnimatedImageViewFetchOperation *operation = [_YYAnimatedImageViewFetchOperation new];
operation.view = self;
operation.nextIndex = nextIndex;
operation.curImage = image;
[_requestQueue addOperation:operation];
@implementation _YYAnimatedImageViewFetchOperation
- (void)main {
    ...
    
    for (int i = 0; i < max; i++, idx++) {
        @autoreleasepool {
            ...
            if (miss) {
                 //解码图片,并且标记
                UIImage *img = [_curImage animatedImageFrameAtIndex:idx];
                img = img.yy_imageByDecoded;
                if ([self isCancelled]) break;
                LOCK_VIEW(view->_buffer[@(idx)] = img ? img : [NSNull null]);
                view = nil;
            }
        }
    }
}
@end

可以看到,_YYAnimatedImageViewFetchOperation解码image图片的操作是通过
NSOperationQueue_requestQueue来异步来处理的

NSMutableDictionary *_buffer; ///< frame buffer

这里cache了显示所需要解压好的图片buffer数据,以便重复使用; 当然这里还有缓存限制和memory告警时清理缓存的机制,我这里就不一一赘述了

参考链接:
https://developer.apple.com/documentation/uikit/uiimage
https://www.jianshu.com/p/72dd074728d8
https://developer.apple.com/documentation/uikit/uiimage

上一篇下一篇

猜你喜欢

热点阅读