iOS Viewcontroller及其他類對dealloc方法調(diào)用的理解
正常情況下余寥,ViewController pop/dismiss之后會被推出棧向瓷,進入ViewController的dealloc方法烂叔。如果沒有走到dealloc方法中须误,則表明沒有被釋放议慰,有內(nèi)存泄露的現(xiàn)象龄糊。一般造成內(nèi)存泄漏的現(xiàn)象分為三種。
1.ViewController中被加入了定時器由驹,而沒有及時的invalidate芍锚。
#import "AViewController.h"
@interface AViewController ()
{
? ? NSTimer *timer;
}
@end
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? self.view.backgroundColor = [UIColor redColor];
? ? timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
}
-(void)updateTime:(id)sender
{
? ? NSLog(@"%@",sender);
? ? NSLog(@"%@",self);
}
-(void)viewWillDisappear:(BOOL)animated
{
? ? [super viewWillDisappear:animated];
? ? [timer invalidate];
}
-(void)dealloc
{
? ? NSLog(@"%@",self);
? ? NSLog(@"AViewController被釋放了哦!");
}
在沒加上[timer invalidate];之前,不會打印AViewController被釋放了哦荔棉!信息闹炉。也就是在此控制器被pop/dismiss時沒有走dealloc方法,沒有被釋放蒿赢。加上[timer invalidate];之后控制器正常釋放了润樱。
2.ViewController里面存在強引用的屬性,比如代理羡棵。
新建一個類作為ViewController的屬性Aclass壹若。
#import <Foundation/Foundation.h>
@protocol AclassProtocolDelegate <NSObject>
-(void)study;
@end
@interface Aclass : NSObject
@property(nonatomic,strong)id<AclassProtocolDelegate> delegate;
@end
#import "Aclass.h"
@implementation Aclass
-(void)dealloc
{
? ? NSLog(@"Aclass被釋放了");
}
@end
#import <UIKit/UIKit.h>
#import "Aclass.h"
@interface AViewController : UIViewController<AclassProtocolDelegate>
@property (nonatomic,strong) Aclass *aclass;
@end
#import "AViewController.h"
@interface AViewController ()
{
? ? NSTimer *timer;
}
@end
@implementation AViewController
-(void)study
{
? ? NSLog(@"今天學(xué)習(xí)了嗎?");
}
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? self.view.backgroundColor = [UIColor redColor];
? ? self.aclass = [[Aclass alloc] init];
? ? self.aclass.delegate = self;
? ? NSLog(@"%@",self.aclass);
? ? timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
}
-(void)updateTime:(id)sender
{
? ? NSLog(@"%@",self);
? ? if ([self.aclass.delegate respondsToSelector:@selector(study)]) {
? ? ? ? [self.aclass.delegate study];
? ? }
}
-(void)viewWillDisappear:(BOOL)animated
{
? ? [super viewWillDisappear:animated];
? ? [timer invalidate];
}
-(void)dealloc
{
? ? NSLog(@"%@",self);
? ? NSLog(@"AViewController被釋放了哦皂冰!");
}
@end
結(jié)果不會走AViewController的dealloc方法打印出AViewController被釋放了哦店展!因為控制器在被pop/dismiss出棧之后,還被里面的aclass.delegate強引用在秃流,相互循環(huán)引用赂蕴。無法釋放。解決辦法有兩個舶胀。A.手動釋放在 [timer invalidate];下面將 self.aclass = nil;
need-to-insert-img
B.將代理的屬性設(shè)置成weak概说。 @property(nonatomic,weak)id<AclassProtocolDelegate> delegate;
need-to-insert-img
3.控制器中的block的循環(huán)引用碧注。
#import <UIKit/UIKit.h>
typedef void (^myBlock)(void);
@interface AViewController : UIViewController<AclassProtocolDelegate>
{
? ? myBlock blk;
}
@end
#import "AViewController.h"
@implementation AViewController
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? self.view.backgroundColor = [UIColor redColor];
? ? blk = ^{
? ? ? ? NSLog(@"self = %@", self);
? ? };
}
-(void)dealloc
{
? ? NSLog(@"%@",self);
? ? NSLog(@"AViewController被釋放了哦!");
}
@end
這樣寫系統(tǒng)會提示Capturing ’self’ strongly in this block is likely to lead to a retain cycle.
need-to-insert-img
當(dāng)pop/dismiss控制器的時候不會走dealloc方法糖赔,因為存在循環(huán)引用萍丐,控制器強引用了block,而block又強引用了控制器,不能進行釋放放典。由于self是__strong修飾逝变,在 ARC 下,當(dāng)編譯器自動將代碼中的 block 從椃芄梗拷貝到堆時壳影,block 會強引用和持有self,而self恰好也強引用和持有了 block弥臼,就造成了傳說中的循環(huán)引用态贤。
解決辦法:
id__weak weakself = self;
? ? blk = ^{
? ? ? ? NSLog(@"self = %@",weakself);
? ? };
即可看到調(diào)用dealloc方法,打印AViewController被釋放了哦醋火!悠汽。
need-to-insert-img
擴展下,如果上面變成如下芥驳。則也會形成循環(huán)引用柿冲。
#import <UIKit/UIKit.h>
typedef void (^myBlock)(void);
@interface AViewController : UIViewController<AclassProtocolDelegate>
{
? ? myBlock blk;
? ? id _obj;
}
@end
#import "AViewController.h"
@implementation AViewController
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? self.view.backgroundColor = [UIColor redColor];
? ? blk = ^{
? ? ? ? NSLog(@"_obj = %@", _obj);
? ? };
}
-(void)dealloc
{
? ? NSLog(@"%@",self);
? ? NSLog(@"AViewController被釋放了哦!");
}
@end
雖然沒有直接使用 self兆旬,卻也存在循環(huán)引用的問題假抄。因為對于編譯器來說,_obj就相當(dāng)于self->_obj丽猬,所以上面的代碼就會變成宿饱。
blk = ^{
? ? ? ? NSLog(@"_obj = %@",self->_obj);
? ? };