內(nèi)存方面常見問題:
1、UIGraphicsEndImageContext
UIGraphicsBeginImageContext和UIGraphicsEndImageContext必須成雙出現(xiàn),不然會造成context泄漏。另外XCode的Analyze也能掃出這類問題。
2、UIWebView
無論是打開網(wǎng)頁,還是執(zhí)行一段簡單的js代碼,UIWebView都會占用APP大量內(nèi)存。而WKWebView不僅有出色的渲染性能,而且它有自己獨立進程,一些網(wǎng)頁相關的內(nèi)存消耗移到自身進程里,最適合取替UIWebView。不過目前蘋果已經(jīng)強制iOS開發(fā)者使用WKWebView
3、autoreleasepool
通常autoreleased對象是在runloop結束時才釋放。如果在循環(huán)里產(chǎn)生大量autoreleased對象,內(nèi)存峰值會猛漲,甚至出現(xiàn)OOM。適當?shù)奶砑觓utoreleasepool能及時釋放內(nèi)存,降低峰值。
4、互相引用
比較容易出現(xiàn)互相引用的地方是block里使用了self,而self又持有這個block,只能通過代碼規(guī)范來避免。另外NSTimer的target、CAAnimation的delegate,是對Obj強引用。使用的時候要注意。
5、大圖片處理
舉個例子一般圖片縮放接口是這樣寫的:
- (UIImage)scaleImage:(UIImage)image newSize:(CGSize)newSize {
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
但處理大分辨率圖片時,往往容易出現(xiàn),原因是-[UIImage drawInRect:]在繪制時,先解碼圖片,再生成原始分辨率大小的bitmap,這是很耗內(nèi)存的。解決方法是使用更低層的ImageIO接口,避免中間bitmap產(chǎn)生: - (UIImage)scaleImageWithData:(NSData)data withSize:(CGSize)size scale:(CGFloat)scale orientation:(UIImageOrientation)orientation {
CGFloat maxPixelSize = MAX(size.width, size.height);
CGImageSourceRef ref = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);
NSDictionary *options = @{(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways:(__bridge id)kCFBooleanTrue,(__bridge id)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithFloat:maxPixelSize]};
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(ref, 0, (__bridge CFDictionaryRef)options);
UIImage *resultImage = [UIImage imageWithCGImage:imageRef scale:scale orientation:orientation];
CGImageRelease(imageRef);
CFRelease(ref);
return resultImage;
}
6、大視圖
大視圖是指View的size過大,自身包含要渲染的內(nèi)容。比如微信里常見的炸群消息,通常幾千甚至幾萬行。如果把它繪制到同一個View里,那將會消耗大量內(nèi)存,同時造成嚴重卡頓。最好做法是把文本劃分成多個View繪制,利用TableView的復用機制,減少不必要的渲染和內(nèi)存占用。