解决卡顿
卡顿产生原因:屏幕上每一帧内容,都是CPU计算后,GPU渲染的结果。当垂直信号(Vsync)产生时,如果CPU计算与GPU渲染的结果没有完成,屏幕会渲染上一帧的内容,从而发生丢帧。(按照60FPS的刷帧率,每隔16ms就会有一次VSync信号)。
主要思路:尽可能减少CPU和GPU的资源消耗。
具体方案:
- 在单元格高度不一的界面中,首先要根据数据结构,将单元格高度计算好,缓存在高度数组中,利用代理将对应高度返回。
注意:
不要频繁调用UIView的frame、transform、bounds,减少CPU的计算 - 可以用CALayer代替某些下划线之类的视图,或者用不到事件处理的地方,即尽量用轻量级对象。UIView之所以可以显示,是因为它有CALayer。除此之外UIView有处理事件的能力
- Auto layout会比直接设置frame消耗更多的CPU资源
- 圆角设置方式:
- 圆角使用CoreGraphics渲染
- 美工直接给圆角图片
- 比直接maskToBounds=YES; cornerRadius>0(二者同时设置)
因为第3种是离屏渲染,需要再当前屏幕缓冲区以外开辟一个新的缓冲区进行渲染操作。离屏渲染的其他操作还有:layer.mask(遮罩)、layer.sgiykdRasterize=YES
// 0.加载图片
UIImage *image = [UIImage imageNamed:@"头像"];
// 1.开启位图上下文,跟图片尺寸一样大
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
// 2.设置圆形裁剪区域,正切与图片
// 2.1创建圆形的路径
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
// 2.2把路径设置为裁剪区域
[path addClip];
// 3.绘制图片
[image drawAtPoint:CGPointZero];
// 4.从上下文中获取图片
UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();
// 5.关闭上下文
UIGraphicsEndImageContext();
_imageView.image = clipImage;
// Graphics绘制方法
- (void)drawCornerPicture{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(200, 400, 200, 200)];
imageView.image = [UIImage imageNamed:@"1"];
// 开启图片上下文
// UIGraphicsBeginImageContext(imageView.bounds.size);
// 一般使用下面的方法
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0);
// 绘制贝塞尔曲线
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:100];
// 按绘制的贝塞尔曲线剪切
[bezierPath addClip];
// 画图
[imageView drawRect:imageView.bounds];
// 获取上下文中的图片
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭图片上下文
UIGraphicsEndImageContext();
[self.view addSubview:imageView];
}
- 图片的size最好和UIImageView的size保持一致,减少CPU的压缩计算
- 控制线程的最大并发量
- 尽量把耗时操作放入子线程,例如:
- boundingReactWithSize(计算文本)
- drawWithReact(文本绘制)
- 图片异步解码:[UIImage imageNamed:]返回的对象,只有当图片渲染时,才会被解码,而且这个解码方式在主线程。因此在异步处理好解码的结果直接渲染,可以减少耗时(图片解码)
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
if (![UIImage shouldDecodeImage:image]) {
return image;
}
@autoreleasepool{
CGImageRef imageRef = image.CGImage;
CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef];
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
size_t bytesPerRow = kBytesPerPixel * width;
// 图片绘制
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
kBitsPerComponent,
bytesPerRow,
colorspaceRef,
kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
if (context == NULL) {
return image;
}
// 绘制图片
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
// 获取图片 ( 完成解码)
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
scale:image.scale
orientation:image.imageOrientation];
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
return imageWithoutAlpha;
}
}
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
// Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
if (image == nil) {
return NO;
}
if (image.images != nil) {
return NO;
}
CGImageRef imageRef = image.CGImage;
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
if (anyAlpha) {
return NO;
}
return YES;
}
耗电优化
- 尽可能降低CPU、GPU功耗
- 少用定时器
- 优化I/O操作(文件读写)
- 尽量不要频繁写入小数据,最好批量一次性写入
- 访问大量数据,dispatch_io提供了基于GCD的异步操作文件I/O的API,可以优化磁盘访问
3.数据较大用数据库
网络优化
- 减少、压缩网络数据。(XML数据格式臃肿,所以JSON流行)
- 最好一次性下载完,减少请求次数。反之,使用断点续传,保障数据不重复请求
- 网络不可用时,停止执行所有网络请求
定位优化
- 如果定位完成,最好关闭定位服务,这样可以让定位硬件断电
- 尽量不使用定位精度最高的KCLLocationAccuracyBest
- 需要后台定位时,尽量设置pauseLocationUpdatesAutomatically = YES;在用户很小移动时,会暂停位置更新
网友评论