1.imageName & imageWithContentsOfFile
| imageNamed | imageWithContentsOfFile |
加载方式区别 | 从缓存中读取 | 直接从文件中加载图片 |
CPU开销 | 大 | 低 |
场景 | 经常使用的场景 | 不是经常使用的场景 |
多个相同 是否重复加载 | 不会 | 会 |
2图片显示流程
001 从磁盘拷贝数据到内核缓冲区(系统调用)
002 从内核缓冲区拷贝数据到用户控件(进程所在)
003 生成UIImageView,把图像数据赋值给UIImageView
004 如果图片未解码,解码为位图数据
005 CATransaction 捕获到UIImageView图层树的变化
006 主线程RunLoop在最后的drawing cycle提交CATransaction
如果数据没有字节对齐,core Animation会再拷贝一份数据进行字节对齐
007 GPU处理位图数据,进行渲染
3.图片解码流程
将PNG JPEG格式图片,显示在图片中的格式是bitmap
需要进行几个专有buffer
Data Buffer :存储在内存中的原始数据 01010101
Image Buffer:存储在内存中的像素点
Frame buffer:帧缓冲,用于显示到显示器上,存储在VRAM中
解码的时机
图片在被设置到UIImageView.image或者layer.contents中之后,在layer被提交到GPU之前CGImage数据才会解码,这一步发生在主线程中,无可避免。
画布重绘解码 将图片用CGContextDrawImage()绘制到画布上,然后把画布的数据取出来当作图片
+ (CGImageRef)CGImageCreateDecoded:(CGImageRef)cgImage orientation:(CGImagePropertyOrientation)orientation {
if (!cgImage) {
return NULL;
}
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
if (width == 0 || height == 0) return NULL;
size_t newWidth;
size_t newHeight;
switch (orientation) {
case kCGImagePropertyOrientationLeft:
case kCGImagePropertyOrientationLeftMirrored:
case kCGImagePropertyOrientationRight:
case kCGImagePropertyOrientationRightMirrored: {
// These orientation should swap width & height
newWidth = height;
newHeight = width;
}
break;
default: {
newWidth = width;
newHeight = height;
}
break;
}
BOOL hasAlpha = [self CGImageContainsAlpha:cgImage];
// iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]`
// Though you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage`
// But since our build-in coders use this bitmapInfo, this can have a little performance benefit
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
CGContextRef context = CGBitmapContextCreate(NULL, newWidth, newHeight, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo);
if (!context) {
return NULL;
}
// Apply transform
CGAffineTransform transform = SDCGContextTransformFromOrientation(orientation, CGSizeMake(newWidth, newHeight));
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); // The rect is bounding box of CGImage, don't swap width & height
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
return newImageRef;
}