一、图像性能优化
1、减少view个数 ,例如聊天的图文混排,使用富文本代替labels,imageviews。
2、减少使用半透明效果,或者不要把半透明加在一个经常变化的view之上,因为,不仅底层view要更新,半透明的也要更新。
3、 shouldRasterize(栅格化) == true,将当前view绘制成image缓存,这个绘制过程本身比较耗时耗内存,但是如果界面很少变化,这种缓存能提升性能。栅格化就是将内容转化成图片。
二、图像性能检测,Core Animation工具
1 Blended像素混合
1.1 当图层有半透明时,如:view.backgroundcolor。
GPU需要进行像素混合,需要先绘制透明层下层的内容,再叠加透明层以达到透明的效果,而不影响帧率的情况下,GPU可绘制的像素是有限制的。
1.2 通常优化方式
- backgroundColor设置为不透明色
- Opaque设置为YES
- 图片能不用透明的切图成不透明
例1:运行结果见图一。
- (void)testBlendedLayer
{
__block CGFloat width = 200;
__block CGFloat leftOffset = (SCREEN_WIDTH - 200)/2.0;
__block CGFloat topOffset = 70;
[self testBlendedLayer:^(UILabel *label) {
label.frame = CGRectMake(leftOffset, topOffset, width, 30);
topOffset += 50;
label.text = @"背景颜色:默认";
}];
[self testBlendedLayer:^(UILabel *label) {
label.frame = CGRectMake(leftOffset, topOffset, width, 30);
topOffset += 50;
label.text = @"背景颜色:半透明";
label.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
}];
[self testBlendedLayer:^(UILabel *label) {
label.frame = CGRectMake(leftOffset, topOffset, width, 30);
topOffset += 50;
label.text = @"背景颜色:不透明";
label.backgroundColor = [UIColor lightGrayColor];
}];
[self testBlendedLayer:^(UILabel *label) {
label.frame = CGRectMake(leftOffset, topOffset, width, 30);
topOffset += 50;
label.text = @"背景颜色:无混合情况";
label.backgroundColor = [UIColor lightGrayColor];
label.layer.masksToBounds = YES;
}];
}
- (void)testBlendedLayer:(void (^) (UILabel *label))construct
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)];
label.textColor = [UIColor blackColor];
if (construct) {
construct(label);
}
[self.view addSubview:label];
}
1:55:47
2、Color Copied images 图片能否需CPU要转码,需要的显示蓝色,如图二所示。
- (void)viewDidLoad {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
UIImage *origin = [UIImage imageNamed:@"16.png"];
UIImage *image = [Util decodeImage:origin toSize:imageView.layer.bounds.size];
imageView.image = origin;
imageView.opaque = YES;
[self.view addSubview:imageView];
[super viewDidLoad];
}
+ (UIImage *)decodeImage:(UIImage *)image toSize:(CGSize)size
{
if (image == nil) { // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
return nil;
}
@autoreleasepool{
// do not decode animated images
if (image.images != nil) {
return image;
}
CGImageRef imageRef = image.CGImage;
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
if (anyAlpha) {
NSLog(@"图片解压失败,存在alpha通道");
return image;
}
// current
CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef));
CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef);
BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown ||
imageColorSpaceModel == kCGColorSpaceModelMonochrome ||
imageColorSpaceModel == kCGColorSpaceModelCMYK ||
imageColorSpaceModel == kCGColorSpaceModelIndexed);
if (unsupportedColorSpace) {
colorspaceRef = CGColorSpaceCreateDeviceRGB();
}
CGFloat scale = [UIScreen mainScreen].scale;
size_t width = size.width;
size_t height = size.height;
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
// kCGImageAlphaNone is not supported in CGBitmapContextCreate.
// Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast
// to create bitmap graphics contexts without alpha info.
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
bitsPerComponent,
bytesPerRow,
colorspaceRef,
kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
// Draw the image into the context and retrieve the new bitmap image without alpha
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
scale:scale
orientation:image.imageOrientation];
if (unsupportedColorSpace) {
CGColorSpaceRelease(colorspaceRef);
}
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
NSLog(@"图片解压成功");
return imageWithoutAlpha;
}
}
3、Offscreen-Rendered工具
- 离屏渲染
在使用圆角、阴影和遮罩等视图功能的时候,图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制,所有就需要在屏幕外的上下文中渲染,即离屏渲染。
产生离屏渲染原因:
shouldRasterize(光栅化)、masks(遮罩)、shadows(阴影)、edge antialiasing(抗锯齿)、group opacity(不透明)、复杂形状设置圆角、渐变
见链接:https://www.cnblogs.com/fishbay/p/7576176.html
4、Color Hits Green and Misses Red 检测栅格化的效果,绿色最佳
栅格化命中显示绿色,没有命中显示红色。见图三cell.rasterizeLbl.layer.shouldRasterize = YES;
当 shouldRasterize 设成 true 时,layer 被渲染成一个 bitmap,并缓存起来,等下次使用时不会再重新去渲染了。实现圆角本身就是在做颜色混合(blending),如果每次页面出来时都blending,消耗太大,这时shouldRasterize = yes,下次就只是简单的从渲染引擎的 cache 里读取那张 bitmap,节约系统资源。
额外收获:如果在滚动 tableView 时,每次都执行圆角设置,肯定会阻塞 UI,设置这个将会使滑动更加流畅。