从很多地方听到过一个概念,重写
- (void)drawRect:(CGRect)rect
方法会造成内存飙升的问题,实践出真知,试了才知道。
场景如下:
一个简易画板view,这里只为了测试重写drawRect会造成的内存问题,不考虑一些画板平移之类的操作。
先上代码,定义一个CpuDrawView类
#import "CpuDrawView.h"
@interface CpuDrawView()
@property (nonatomic, strong) NSMutableArray *paths;
@end
@implementation CpuDrawView
#pragma mark - init
- (instancetype)init
{
self = [super init];
if (self) {
self.backgroundColor = [UIColor whiteColor];
}
return self;
}
#pragma mark - drawRect
- (void)drawRect:(CGRect)rect
{
for (UIBezierPath *path in self.paths) {
// 连接处样式
[path setLineJoinStyle:kCGLineJoinRound];
// 头尾样式
[path setLineCapStyle:kCGLineCapRound];
[path stroke];
}
}
#pragma mark - touch
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
UIBezierPath *path = [UIBezierPath bezierPath];path.lineWidth = 5;
[path moveToPoint:point];
[self.paths addObject:path];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
[[self.paths lastObject] addLineToPoint:point];
[self setNeedsDisplay];
}
#pragma getter
- (NSMutableArray *)paths
{
if (!_paths) {
_paths = [NSMutableArray array];
}
return _paths;
}
@end
在VC中的使用
/**
drawRect方式画板 cpu绘制
*/
- (IBAction)cpu_Draw:(id)sender {
CpuDrawView *cpuDrawView = [[CpuDrawView alloc] init];
cpuDrawView.frame = CGRectMake(0, -kScreenHeight, kScreenWidth * 5, 2 * kScreenHeight - 100);
[self.view addSubview:cpuDrawView];
}
在注释掉drawRect方法之后,app启动并创建cpuDrawView的内存占用如下:
//- (void)drawRect:(CGRect)rect
//{
// for (UIBezierPath *path in self.paths) {
// // 连接处样式
// [path setLineJoinStyle:kCGLineJoinRound];
// // 头尾样式
// [path setLineCapStyle:kCGLineCapRound];
// [path stroke];
// }
//}
image.png
在如下两种方式下内存占用如下图
- (void)drawRect:(CGRect)rect
{
// for (UIBezierPath *path in self.paths) {
// // 连接处样式
// [path setLineJoinStyle:kCGLineJoinRound];
// // 头尾样式
// [path setLineCapStyle:kCGLineCapRound];
// [path stroke];
// }
}
//或者
- (void)drawRect:(CGRect)rect
{
for (UIBezierPath *path in self.paths) {
// 连接处样式
[path setLineJoinStyle:kCGLineJoinRound];
// 头尾样式
[path setLineCapStyle:kCGLineCapRound];
[path stroke];
}
}
image.png
可以看出,只要重写了drawRect方法,在创建的view不是特别大的情况下,内存已经出现了飙升,这个已经印证了上面的结论。
具体原因有一个UIView->CALayer->content(寄宿图)的概念,详细分析见 内存恶鬼drawRect - 谈画图功能的内存优化
内存恶鬼中提到用CAShaperLayer矢量图去解决类似问题,CAShaperLayer不会通过bitmap的方式去进行绘制,而且也不会创建寄宿图。
本着眼见为实的态度,我又写了一个使用UIBezierPath和CAShaperLayer结合使用进行绘制的case,见代码:
#import "GpuDrawView.h"
@interface GpuDrawView()
@property (nonatomic, strong) NSMutableArray *paths;
// 预留做撤销使用
@property (nonatomic, strong) NSMutableArray *layers;
@end
@implementation GpuDrawView
#pragma mark - init
- (instancetype)init
{
self = [super init];
if (self) {
self.backgroundColor = [UIColor whiteColor];
}
return self;
}
#pragma mark - touch
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
UIBezierPath *path = [UIBezierPath bezierPath];
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinRound;
[path moveToPoint:point];
[self.paths addObject:path];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
UIBezierPath *path = [self.paths lastObject];
[path addLineToPoint:point];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.lineWidth = 5;
layer.strokeStart = 0;
layer.strokeEnd = 1;
layer.lineCap = kCALineCapRound;
layer.lineJoin = kCALineJoinRound;
layer.strokeColor = [UIColor redColor].CGColor;
layer.fillColor = [UIColor clearColor].CGColor;
[self.layers addObject:layer];
layer.path = path.CGPath;
[self.layer addSublayer:layer];
}
#pragma mark - getter
- (NSMutableArray *)paths
{
if (!_paths) {
_paths = [NSMutableArray array];
}
return _paths;
}
- (NSMutableArray *)layers
{
if (!_layers) {
_layers = [NSMutableArray array];
}
return _layers;
}
@end
实际操作证明,使用CAShaperLayer方式进行绘制内存不会有明显变化。
你也可以下载本文的demo
网友评论