ARC下可以重写dealloc方法并在viewController被释放后自动调用,重写该方法时不能显示调用[super dealloc],因为系统会自动帮你调用父类的dealloc方法。
控制器在被pop后移出栈后会被释放,但有些时候会发现控制器出栈的时候不会调用dealloc方法,归根结底,是因为当前控制器被某个对象强引用,控制器的引用计数不为0,系统无法帮你释放这部分内存;最近就遇到viewController被pop后不调用dealloc的问题,查看了一下是因为viewController中的代理问题,这个viewController中的代理是单利对象的代理,并且该代理是一对多,用数组来处理的,当把该viewController添加到代理数组后,别的viewController调用这个popToViewController忘把该viewController从代理数组里removed调从而导致这个数组一直强引用该viewController。
下面我总结一下viewController被pop后不调用dealloc常见情况
1.控制器中NSTimer没有被销毁
当viewController中存在NSTimer时,需要特别注意,当调用
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES]
时,因为target:self,也就是引用了当前
viewController,导致控制器的引用计数加1,如果没有将这个NSTimer销毁,它将一直保留该viewController无法释放,也就不会调用dealloc方法。所以一般要在viewWillDisappear之前需要把控制器用到的NSTimer
[timer invalidate]; // 销毁timer
timer = nil; // 置nil
2.
viewController中的代理不是weak属性或在pop之前没把代理移除掉
例如@property(nonatomic,weal)id delegate;代理要使用弱引用,因为自定义控件是加载在视图控制器中的,视图控制器view对自定义控件是强引用,如果代理属性设置为strong,则意味着delegate对视图控制器也进行了强引用,会造成循环引用。从而导致控制器无法释放,最终导致内存泄露;自定义对象里定义
NSMutableArray<id<MVCameraClientObserver> >* _observers把控制器添加到这个数组中的时候,这个数组对控制器强引用,所以在pop之前必须先removed掉
3.viewController中的block的循环引用
在ARC下,block会把它里面的所有对象强引用,包括当前控制器self,因为有可能会出现循环引用的问题。比如viewController中有个block属性,在block中又强引用了self或者其他成员变量,那么viewController与自己的block属性就形成了循环引用,导致viewController无法释放。
// ARC enabled
/************** MyObject Class **************/
typedefvoid(^myBlock)(
void);
@interfaceMyObject:
NSObject
{
myBlock blk;
}
@end
@implementationMyObject
- (
id)init
{
self=[superinit];
blk = ^{
NSLog(
@"self = %@",
self);
};
returnself;
}
- (
void)dealloc
{
NSLog(
@"dealloc");
}
@end
/************** main function **************/
int main()
{
id myObject=[[MyObjectalloc] init];
NSLog(
@"%@",myObject);
return
0;
}
由于self是strong修饰,在arc下,当编译器自动将代码中的block从栈拷贝到堆时,block会强引用和持有self。而self恰好也强引用和持有block,就造成循坏引用。
由于循坏引用的存在,造成在main()函数结束时,内存仍然无法释放,即内存泄漏。
为了避免这种情况的发生,可以在变量声明时用_weak修饰符修饰变量self,让block不强引用self,从而破除循环,
- (id)init
{
self = [super init];
id __weak tmp = self;
blk = ^{NSLog(@"self = %@", tmp);};
return self;
}
在看一个例子
@interface MyObject : NSObject
{
myBlock blk;
id _obj;
}
@end
@implementation MyObject
- (
id)init
{
self = [
super init];
blk = ^{
NSLog(
@"_obj = %@", _obj); };
return
self;
}
...
...
@end
上面的例子中,虽然没有直接使用self,却也存在循环引用的问题。因为对于编译器来说_obj就相当于self->_obj,s所以上面的代码就会变成
blk = ^{ NSLog(@"_obj = %@", self->_obj); };