viewController被POP后不調(diào)用dealloc的問(wèn)題

ARC下可以重寫dealloc方法并在viewController被釋放后自動(dòng)調(diào)用,重寫該方法時(shí)不能顯式調(diào)用[super dealloc],因?yàn)橄到y(tǒng)會(huì)自動(dòng)幫你調(diào)用父類的dealloc方法。

控制器在被pop后移出棧后會(huì)被釋放,但有些時(shí)候會(huì)發(fā)現(xiàn)控制器出棧的時(shí)候不會(huì)調(diào)用dealloc方法,歸根結(jié)底,是因?yàn)楫?dāng)前控制器被某個(gè)對(duì)象強(qiáng)引用了,控制器的引用計(jì)數(shù)不為0,系統(tǒng)無(wú)法幫你釋放這部分內(nèi)存。原因大致有以下幾點(diǎn):

控制器中NSTimer沒(méi)有被銷毀
當(dāng)viewController中存在NSTimer時(shí),需要特別注意,當(dāng)調(diào)用

[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:)  userInfo:nil repeats:YES]

時(shí),因?yàn)?target:self ,也就是引用了當(dāng)前viewController,導(dǎo)致控制器的引用計(jì)數(shù)加1,如果沒(méi)有將這個(gè)NSTimer 銷毀,它將一直保留該viewController,無(wú)法釋放,也就不會(huì)調(diào)用dealloc方法。所以,需要在viewWillDisappear之前需要把控制器用到的NSTimer銷毀。

[timer invalidate]; // 銷毀timer
timer = nil; // 置nil

viewController中的代理不是weak屬性
例如@property (nonatomic, weak) id delegate;代理要使用弱引用,因?yàn)樽远x控件是加載在視圖控制器中的,視圖控制器view對(duì)自定義控件是強(qiáng)引用,如果代理屬性設(shè)置為strong,則意味著delegate對(duì)視圖控制器也進(jìn)行了強(qiáng)引用,會(huì)造成循環(huán)引用。導(dǎo)致控制器無(wú)法被釋放,最終導(dǎo)致內(nèi)存泄漏。

viewController中block的循環(huán)引用
在ARC下,block會(huì)把它里面的所有對(duì)象強(qiáng)引用,包括當(dāng)前控制器self,因此有可能會(huì)出現(xiàn)循環(huán)引用的問(wèn)題。比如viewController中有個(gè)block屬性,在block中又強(qiáng)引用了self或者其他成員變量,那么這個(gè)viewController與自己的block屬性就形成循環(huán)引用,導(dǎo)致viewController無(wú)法釋放。

// 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 下,當(dāng)編譯器自動(dòng)將代碼中的 block 從??截惖蕉褧r(shí),block 會(huì)強(qiáng)引用和持有self,而self恰好也強(qiáng)引用和持有了 block,就造成了傳說(shuō)中的循環(huán)引用。

ddddd .png

由于循環(huán)引用的存在,造成在main()函數(shù)結(jié)束時(shí),內(nèi)存仍然無(wú)法釋放,即內(nèi)存泄露。編譯器也會(huì)給出警告信息

warning: capturing 'self' strongly in this block is likely to lead to a retain cycle [-Warc-retain-cycles]
blk = ^{NSLog(@"self = %@", self);};
note: Block will be retained by an object strongly retained by the captured object
blk = ^{NSLog(@"self = %@", self);};

為了避免這種情況發(fā)生,可以在變量聲明時(shí)用__weak修飾符修飾變量self,讓 block 不強(qiáng)引用self,從而破除循環(huán)。iOS4 和 Snow Leopard 由于對(duì) weak 的支持不夠完全,可以用__unsafe_unretained代替。

- (id)init
{
    self = [super init];
    id __weak tmp = self;
    blk = ^{NSLog(@"self = %@", tmp);}; 
    return self;
}
Paste_Image.png

再看一個(gè)例子:

@interface MyObject : NSObject
{
   myBlock  blk;
   id _obj; 
}
@end
@implementation MyObject 

- (id)init
{
     self = [super init];
     blk = ^{ NSLog(@"_obj = %@", _obj); }; 
     return self;
}
...
...
@end

上面的例子中,雖然沒(méi)有直接使用 self,卻也存在循環(huán)引用的問(wèn)題。因?yàn)閷?duì)于編譯器來(lái)說(shuō),_obj就相當(dāng)于self->_obj,所以上面的代碼就會(huì)變成

 blk = ^{ NSLog(@"_obj = %@", self->_obj); };

參考文章 [block沒(méi)那么難(三):block和對(duì)象的內(nèi)存管理]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容