ARC下可以重寫dealloc方法並在viewController被釋放後自動調用,重寫該方法時不能顯式調用[super dealloc],因為系統會自動幫你調用父類的dealloc方法。
控制器在被pop後會被釋放,但有些時候會發現控制器有時候不會調用dealloc方法,歸根結底,是因為當前控制器被某個對象強引用了,控制器的引用計數不為0,系統無法幫你釋放這部分記憶體。原因大致有以下幾點:
控制器中NSTimer沒有被銷毀
當viewController中存在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
viewController中的代理不是weak屬性
例如@property (nonatomic, weak) id delegate;代理要使用弱引用,因為自定義控件是加載在視圖控制器中的,視圖控制器view對自定義控件是強引用,如果代理屬性設置為strong,則意味著delegate對視圖控制器也進行了強引用,會造成循環引用。導致控制器無法被釋放,最終導致記憶體洩漏。
例如@property (nonatomic, weak) id delegate;代理要使用弱引用,因為自定義控件是加載在視圖控制器中的,視圖控制器view對自定義控件是強引用,如果代理屬性設置為strong,則意味著delegate對視圖控制器也進行了強引用,會造成循環引用。導致控制器無法被釋放,最終導致記憶體洩漏。
viewController中block的循環引用
在ARC下,block會把它裡面的所有對象強引用,包括當前控制器self,因此有可能會出現循環引用的問題。比如viewController中有個block屬性,在block中又強引用了self或者其他成員變量,那麼這個viewController與自己的block屬性就形成循環引用,導致viewController無法釋放。
在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,就造成了傳說中的循環引用。
ddddd .png
由於循環引用的存在,造成在main()函數結束時,記憶體仍然無法釋放,即記憶體洩露。編譯器也會給出警告信息
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);};
為了避免這種情況發生,可以在變量聲明時用weak修飾符修飾變量self,讓 block 不強引用self,從而破除循環。 iOS4 和 Snow Leopard 由於對 weak 的支持不夠完全,可以用unsafe_unretained代替。
- (id)init
{
self = [super init];
id __weak tmp = self;
blk = ^{NSLog(@"self = %@", tmp);};
return self;
}
Paste_Image.png
再看一個例子:
@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,所以上面的代碼就會變成
blk = ^{ NSLog(@"_obj = %@", self->_obj); };
出處來源:http://www.jianshu.com/p/58f43fcbc197
沒有留言:
張貼留言