DrawRect內(nèi)存飆升

從很多地方聽到過一個概念萌抵,重寫

- (void)drawRect:(CGRect)rect

方法會造成內(nèi)存飆升的問題稿饰,實(shí)踐出真知缰儿,試了才知道畦粮。
場景如下:
一個簡易畫板view,這里只為了測試重寫drawRect會造成的內(nèi)存問題乖阵,不考慮一些畫板平移之類的操作宣赔。
先上代碼,定義一個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啟動并創(chuàng)建cpuDrawView的內(nèi)存占用如下:

//- (void)drawRect:(CGRect)rect
//{
//    for (UIBezierPath *path in self.paths) {
//        // 連接處樣式
//        [path setLineJoinStyle:kCGLineJoinRound];
//        // 頭尾樣式
//        [path setLineCapStyle:kCGLineCapRound];
//        [path stroke];
//    }
//}
image.png

在如下兩種方式下內(nèi)存占用如下圖

- (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方法儒将,在創(chuàng)建的view不是特別大的情況下,內(nèi)存已經(jīng)出現(xiàn)了飆升对蒲,這個已經(jīng)印證了上面的結(jié)論钩蚊。
具體原因有一個UIView->CALayer->content(寄宿圖)的概念贡翘,詳細(xì)分析見 內(nèi)存惡鬼drawRect - 談畫圖功能的內(nèi)存優(yōu)化
內(nèi)存惡鬼中提到用CAShaperLayer矢量圖去解決類似問題,CAShaperLayer不會通過bitmap的方式去進(jìn)行繪制砰逻,而且也不會創(chuàng)建寄宿圖鸣驱。
本著眼見為實(shí)的態(tài)度,我又寫了一個使用UIBezierPath和CAShaperLayer結(jié)合使用進(jìn)行繪制的case蝠咆,見代碼:

#import "GpuDrawView.h"

@interface GpuDrawView()

@property (nonatomic, strong) NSMutableArray *paths;
// 預(yù)留做撤銷使用
@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

實(shí)際操作證明踊东,使用CAShaperLayer方式進(jìn)行繪制內(nèi)存不會有明顯變化。
你也可以下載本文的demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刚操,一起剝皮案震驚了整個濱河市闸翅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菊霜,老刑警劉巖坚冀,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鉴逞,居然都是意外死亡记某,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門华蜒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辙纬,“玉大人,你說我怎么就攤上這事叭喜『丶穑” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵捂蕴,是天一觀的道長譬涡。 經(jīng)常有香客問我,道長啥辨,這世上最難降的妖魔是什么涡匀? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮溉知,結(jié)果婚禮上陨瘩,老公的妹妹穿的比我還像新娘。我一直安慰自己级乍,他們只是感情好舌劳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著玫荣,像睡著了一般甚淡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捅厂,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天贯卦,我揣著相機(jī)與錄音资柔,去河邊找鬼。 笑死撵割,一個胖子當(dāng)著我的面吹牛贿堰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播睁枕,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼官边,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了外遇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤契吉,失蹤者是張志新(化名)和其女友劉穎跳仿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐晶,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菲语,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惑灵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片山上。...
    茶點(diǎn)故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖英支,靈堂內(nèi)的尸體忽然破棺而出佩憾,到底是詐尸還是另有隱情,我是刑警寧澤干花,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布妄帘,位于F島的核電站,受9級特大地震影響池凄,放射性物質(zhì)發(fā)生泄漏抡驼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一肿仑、第九天 我趴在偏房一處隱蔽的房頂上張望致盟。 院中可真熱鬧,春花似錦尤慰、人聲如沸馏锡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眷篇。三九已至,卻和暖如春荔泳,著一層夾襖步出監(jiān)牢的瞬間蕉饼,已是汗流浹背虐杯。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昧港,地道東北人擎椰。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像创肥,于是被迫代替她去往敵國和親达舒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容