1 循環(huán)引用
不建議使用:
2 使用單例的的一些情況
在使用單例的時(shí)候要注意窜醉,特別是單例含有block回調(diào)方法時(shí)候埋同。有些單例會(huì)強(qiáng)持有這些block蚯根。這種情況雖然不是循環(huán)引用琼锋,但也是造成了喜歡引用印屁。所以在使用單例的時(shí)候要清楚。如系統(tǒng)有些方法這樣使用會(huì)造成無(wú)法釋放:
- (void)viewDidLoad {
[super viewDidLoad];
self.obser = [[NSNotificationCenter defaultCenter] addObserverForName:@"boyce" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
self.name = @"boyce";
}];
}
- (void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self.obser];
}
這里就造成了內(nèi)存泄漏斩例,這是因?yàn)镹SNotificationCenter強(qiáng)引用了usingBlock雄人,而usingBlock強(qiáng)引用了self,而NSNotificationCenter是個(gè)單例不會(huì)被釋放,而self在被釋放的時(shí)候才會(huì)去把self.obser從NSNotificationCenter中移除础钠。類(lèi)似的情況還有很多恰力,比如一個(gè)數(shù)組中對(duì)象等等。這些內(nèi)存泄漏不容易發(fā)現(xiàn)旗吁。
3 NSTimer
NSTimer的target持有self
NSTimer會(huì)造成循環(huán)引用踩萎,timer會(huì)強(qiáng)引用target即self,一般self又會(huì)持有timer作為屬性很钓,這樣就造成了循環(huán)引用香府。
那么,如果timer只作為局部變量码倦,不把timer作為屬性呢企孩?同樣釋放不了,因?yàn)樵诩尤雛unloop的操作中袁稽,timer被強(qiáng)引用勿璃。而timer作為局部變量,是無(wú)法執(zhí)行invalidate的推汽,所以在timer被invalidate之前补疑,self也就不會(huì)被釋放。
NSTimer *timer = [NSTimer timerWithTimeInterval:10 target:self selector:@selector(commentAnimation) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
解決方法:
主動(dòng)stoptimer歹撒,至少是不能在dealloc中stoptimer的莲组。另外可以設(shè)置一個(gè)中間類(lèi),把target變成中間類(lèi)暖夭。
4 NSURLSession
NSURLSession *section = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
NSURLSessionDataTask *task = [section dataTaskWithURL:[NSURL URLWithString:path]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//Do something
}];
[task resume];
和NSTimer問(wèn)題類(lèi)似胁编,這里NSURLSession會(huì)強(qiáng)引用了self。同時(shí)本地SSL會(huì)對(duì)一個(gè)NSURLSession緩存一段時(shí)間鳞尔。所以即使沒(méi)有強(qiáng)引用。也會(huì)造成內(nèi)存泄漏早直。這里比較好的使用單例[NSURLSession sharedSession]
5 非OC對(duì)象的內(nèi)存問(wèn)題
在OC對(duì)象轉(zhuǎn)換為非OC對(duì)象時(shí)候寥假,要進(jìn)行橋接。要把對(duì)象的控制權(quán)由ARC轉(zhuǎn)換為程序員自己控制霞扬,這時(shí)候程序員要自己控制對(duì)象創(chuàng)建和釋放糕韧。如下面的簡(jiǎn)單代碼
NSString *name = @"boyce";
CFStringRef cfStringRef = (__bridge CFStringRef) name;
CFRelease(cfStringRef);
6 其他泄漏情況
如果present一個(gè)UINavigationController,如果返回的姿勢(shì)不正確喻圃。會(huì)造成內(nèi)存泄漏
UIViewController *vc = [[UIViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:NULL];
如果在UIViewController里邊調(diào)用的是如下代碼萤彩,那么就會(huì)造成內(nèi)存泄漏,這里邊測(cè)試發(fā)現(xiàn)vc是沒(méi)有被釋放的斧拍。
[self dismissViewControllerAnimated:YES completion:NULL];
解決方法:
if (self.navigationController.topViewController == self) {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
7 ARC內(nèi)存泄露的檢測(cè)
7.1 使用Xcode自帶工具Instrument
7.2 在對(duì)象dealloc中進(jìn)行打印
我們生成的對(duì)象雀扶,在即將釋放的時(shí)候,會(huì)調(diào)用dealloc方法。所以我們可以在dealloc打印當(dāng)前對(duì)象已經(jīng)釋放的消息愚墓。如果沒(méi)有釋放予权,對(duì)象的dealloc方法就永遠(yuǎn)不會(huì)執(zhí)行,此時(shí)我們知道發(fā)生了內(nèi)存泄露。