【iOS開發】內存管理之UIViewController無法正常釋放的常見問題 – iPhone手機開發 iPhone軟體開發教學課程

引言

【iOS開發】內存管理之UIViewController無法正常釋放的常見問題,iOS開發中內存管理是很重要的,如果處理不當,輕則會導致內存泄漏、莫名其妙的bug等等,重則可能導致程序崩潰。本文總結瞭在iOS開發中三個可能導致控制器不能正常釋放的常見問題。

導致控制器不能正常釋放的原因?

控制器的引用計數不為0,也就是說被其他對象強引用,因此不能正常釋放。

如何知道控制器是否已經正常釋放?

在ARC模式下,控制器在徹底銷毀之前會調用dealloc方法,並自動調用[super dealloc]方法。因此,可以重寫基類的dealloc方法,輸出控制器銷毀提示信息,如果控制器沒有調用dealloc方法,說明不能正常釋放。

- (void)dealloc {
    NSLog(@"%@ dealloc",NSStringFromClass([self class]));
}

問題一:block引發的循環引用

無弱引用聲明的情況下,block持有它裡面所有對象的所有權,即為強引用,所以當在block裡面使用self的時候,可能會導致控制器不能正常釋放。

比如:objectB擁有callbackBlock屬性,在objectA中設置該屬性

[objectB setCallbackBlock:^{
    [self excuBlock];
}];

在block中引用瞭自身方法(或變量),形成瞭循環引用。

解決方法:

在block中使用對自身對象的弱引用來替換self

__weak __typeof(self)weakSelf = self;
[objectB setCallbackBlock:^{

    __strong __typeof(weakSelf)strongSelf = weakSelf;
    [strongSelf excuBlock];

}];

如果在block使用瞭成員變量,也要使用其弱引用,以 _dataSource為例:

__weak typeof(_dataSource) weakDataSource = _dataSource;

問題二:強引用的delegate引發的循環引用

如果一個delegate屬性的聲明是strong的時候,會持有自身控制器的所有權,導致控制器不能正常釋放。

比如:

CustomView的delegate聲明

@property (nonatomic, strong) id delegate;
在控制器中賦值

self.customView.delegate = self;
這樣,造成self對customView強引用,customView對self強引用,引發循環引用。

解決方法:

對代理使用弱引用

@property (nonatomic, weak) id delegate;

問題三:使用瞭NSTimer沒有銷毀

當我們使用NSTimer的方法

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];

時,定時器對象會對它的target(即self:當前控制器)持有強引用,如果定時器不銷毀,則控制器無法釋放。

解決方法:

在- (void)viewWillDisappear:(BOOL)animated或者- (void)viewDidDisappear:(BOOL)animated或者其他確定離開當前控制器的方法中銷毀定時器。

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    if (self.timer != nil) {
        [self.timer invalidate];
        self.timer = nil;
    }
}

發佈留言