viewController被pop后不调用dealloc的问题

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); };

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值